Garbage collector memory leak "feature"?

Vladimir Panteleev thecybershadow at gmail.com
Thu Oct 11 05:33:08 PDT 2007


On Thu, 11 Oct 2007 14:44:04 +0300, Frits van Bommel <fvbommel at remwovexcapss.nl> wrote:

> First of all, the size and layout of a stack frame are usually pretty
> constant throughout the execution of a function. DMD and IIRC GDC as
> well just subtract a constant from the stack pointer at the beginning of
> a function to allocate all local variables[0]. Only function calls can
> sometimes change the layout (if their parameters are pushed instead of
> MOVed into place). The latter will be even less of an issue on
> architectures (such as amd64) where several parameters are passed in
> registers.
> If we allow typeless "gaps" in the stack (such as frames for non-D
> functions and perhaps function parameters that aren't included in the
> stack frame descriptions of the calling functions) those will
> unfortunately also need to be treated conservatively.
>
> On architectures I'm aware of (mostly x86 & amd64) the address of the
> current stack frame is held in a register where it can be easily found
> by the GC, and the current instruction pointer can be used to perform
> the lookup in the table I described. This does mean that things like
> GCCs -fomit-frame-pointer shouldn't be used (which it isn't by default),
> but other than that it should work with all existing code without
> modification. If there are architectures[1] where the address of the
> current stack frame can't be defined in a way that remains constant
> throughout the execution of a function[2] some other solution may have
> to be found there.
>
>
> [0] Of course, if we model this as "one description per function" there
> may be some false positives if the GC pauses the thread before all local
> variables are initialized, but this should only happen for a single
> function per thread per GC run.
> [1] Including x86/amd64 gcc with -fomit-frame-pointer
> [2] Or at least throughout large sections of functions

Actually, while thinking about it, I got a better idea. 
The compiler knows the exact layout of the stack frame at any point of the function's execution.
Thus, the compiler could build tables of stack layout bits for various segments of the function (the boundaries of such a segment would be branches and calls). Then, during a GC pass, the GC would look at the instruction pointer of the thread to retrieve the current stack layout for that thread/stack frame.
This way, there isn't any cost during execution - just during collection.

Downsides:
1) needs extra information that would increase binary size (most likely less than generating code that would save stack description at runtime, though)
2) may involve complex changes to the compiler
3) will make GC scanning slower (it would have to do lookups for every stack frame in every thread)
4) does not apply to non-D code using D memory (assembly code, statically or dynamically linked non-D libraries, etc.) - these would have to be conservative, unless we force the user to pass only "non-managed" memory to non-D code
4b) if the external code doesn't use stack frames, I think it's impossible to find any stack frames at all without heuristics

The question is, however: is conservative scanning of the stack that bad? IMO, it's much less problematic just to tell the user to store large amounts of pseudo-random/pointer-like data in the heap or in static arrays (data segment).

-- 
Best regards,
 Vladimir                          mailto:thecybershadow at gmail.com



More information about the Digitalmars-d mailing list