Greedy memory handling

Dmitry Olshansky dmitry.olsh at gmail.com
Thu Sep 12 08:50:25 PDT 2013


12-Sep-2013 17:51, H. S. Teoh пишет:
> On Thu, Sep 12, 2013 at 08:27:59AM +0200, Jacob Carlborg wrote:
>> On 2013-09-11 10:06, monarch_dodra wrote:
>>> I have a function that will *massively* benefit from having a
>>> persistent internal buffer it can re-use (and grow) from call to
>>> call, instead of re-allocating on every call.
>>>
>>> What I don't want is either of:
>>> 1. To set a fixed limitation of size, if the user ends up making
>>> repeated calls to something larger to my fixed size.
>>> 2. For a single big call which will allocate a HUGE internal buffer
>>> that will consume all my memory.
>>>
>>> What I need is some sort of lazy buffer. Basically, the allocation
>>> holds, but I don't want the to prevent the GC from collecting it if
>>> it deems it has gotten too big, or needs more memory.
>>>
>>> Any idea on how to do something like that? Or literature?
>>
>> How about keeping a stack or static buffer. If that gets too small
>> use a new buffer. When you're done with the new buffer set it to
>> null to allow the GC to collect it. Then repeat.
> [...]
>
> The problem is, he wants to reuse the buffer next time if the GC hasn't
> collected it yet.
>
> Here's an idea, though. It doesn't completely solve the problem, but it
> just occurred to me that "weak pointers" (i.e., ignored by the GC for
> the purposes of marking) can be simulated by XOR'ing the pointer value
> with some mask so that it's not recognized as a pointer by the GC. This
> can be encapsulated by a weak pointer struct that automatically does the
> translation:
>
> 	struct WeakPointer(T) {
> 		enum size_t mask = 0xdeadbeef;
> 		union Impl {
> 			T* ptr;
> 			size_t uintVal;
> 		}
> 		Impl impl;
> 		void set(T* ptr) @system {
> 			impl.ptr = ptr;
> 			impl.uintVal ^= mask;
> 		}
> 		T* get() @system {
> 			Impl i = impl;
> 			i.uintVal ^= mask;
> 			return i.ptr;
> 		}
> 	}
>
> 	WeakPointer!Buffer bufferRef;
>
> 	void doWork(Args...) {
> 		T* buffer;
> 		if (bufferRef.get() is null) {
> 			// Buffer hasn't been allocated yet
> 			buffer = allocateNewBuffer();
> 			bufferRef.set(buffer);
> 		} else {
> 			void *p;
> 			core.memory.GC.getAttr(p);

This line above is not 100% good idea .. at least with deadbeaf as mask.

If we do know what OS you compile for we may just flip the say upper bit 
and get a pointer into kernel space (and surely that isn't in GC pool). 
Even then your last paragraph pretty much destroys it.


Better option is to have finalizer hooked up to set some flag. Then 
_after_ restoring the pointer we consult that flag variable.

> 			if (p is null || p != bufferRef.get()) {
> 				// GC has collected previous buffer
> 				buffer = allocateNewBuffer();
> 				bufferRef.set(buffer);
> 			}
> 		}
> 		useBuffer(buffer);
> 		...
> 	}
>
> Note that the inner if block is not 100% safe, because there's no
> guarantee that even if the base pointer of the block hasn't changed, the
> GC hasn't reallocated the block to somebody else. So this part is still
> yet to be solved.
>
>
> T
>


-- 
Dmitry Olshansky


More information about the Digitalmars-d-learn mailing list