Memory management dilemma

Jeff Parsons jeffrparsons at optusnet.com.au
Mon May 29 06:48:46 PDT 2006


Daniel Keep wrote:

> 
> Hi.  My computer just blue-screened while replying to this, so I hope
> you appreciate me typing all this out again :P
> 

I certainly do; this has been really damn helpful. :)

> 
> If you want to pass stuff by-value, you can use a struct.
> 
> Catch: no constructors or destructors.  But, you can do this instead:
> 
> # struct Vector3D
> # {
> #     double x, y, z;
> #
> #     static Vector3D opCall(double x, double y, double z)
> #     {
> #         Vector3D result;
> #         result.x = x; result.y = y; result.z = y;
> #         return result;
> #     }
> # }
> #
> # Vector3D a = Vector3D(1,2,3);
> 

You've won me over. This certainly solves the "millions of temporaries 
being created" issue, for one!

> 
> Three main ways, actually:
> 
> 1. Manually 'deleting' stuff: no fun at all.

Would it still be useful to do this sometimes in deconstructors if I 
know a few members that can safely be cleaned up immediately, so the 
garbage collector doesn't have to sift through things later? Or isn't 
this likely to give me any advantage at all?

> 2. Using 'auto'.  Any object variable marked with 'auto' will
> automatically destroy itself at the end of it's scope.  Example:
> 
> # {
> #     // ...
> #
> #     auto Foo bar = new Foo;
> #
> #     // ...
> #
> #     {
> #
> #         auto Foo baz = new Foo;
> #
> #     } // baz is destroyed here
> #
> #     // ...
> #
> # } // bar is destroyed here
> 
> One thing to watch out for:
> 
> Auto-deleted variable:
> #	auto Foo bar = new Foo;
> 
> Not auto-deleted, with type inference:
> #	auto bar = new Foo;
> 
> 'auto' without a type name after it means that D will work out the type
> of the variable itself.  Just watch out for it :)
> 
> If you want to make sure instances of a particular class are always
> 'auto', you can put the 'auto' keyword out the front of the class
> declaration:
> 
> # auto class Foo
> # {
> #     // ...
> # }
> #
> # // MUST be declared auto:
> # auto Foo a;
> # Foo a; // <-- this won't compile
> 
> However, keep in mind that 'auto' objects can't be put into 'out' or
> 'inout' function arguments, you can't have global 'auto' variables, you
> can't have 'auto' members, and you can't return them out of functions [1].
> 
> 3. Using 'scope(exit)'.  You use 'scope(exit)' like a control statement:
> any statement (or block of statements) you put after a 'scope(exit)'
> will be executed when control leaves that scope.  For example:
> 
> # {
> #
> #     // ...
> #
> #     Foo bar = new Foo;
> #     scope(exit) delete bar;
> #
> #     // ...
> #
> # } // 'delete bar' is executed here
> 
> Please note that 'scope(exit)' blocks will execute irrespective of HOW
> you leave the scope: a return statement, break statement, goto or an
> exception.
> 
> There's also 'scope(fail)' which only executes if you leave the scope
> via an exception, and 'scope(success)' for when you do NOT leave because
> of an exception :)

Noted and understood; I'll certainly be making much use of -all- of that! :)

> As for dealing with temporaries (which I know I haven't actually
> answered :P), then... we'll I don't know.  Unless you keep a reference
> to each temporary object in an expression, I suppose you'd have to leave
> the GC to handle that.
> 
> That or, again, use structs.

Yeah, I think I'd be going for structs there. For one, I don't see it 
being an issue expect in cases like vectors and matrices where they're 
likely to be involved in a lot of number crunching.

> I'm assuming you mean using 'std.gc.disable()' when you say 'no gc active'.
> 
> In that case, nothing is collected.  If you run out of memory, then you
> get an OutOfMemory exception.

I wasn't actually, because I was under the (now seemingly misguided) 
impression that the garbage collector wasn't initialized by default. And 
also the impression that it would be practical attempting to live 
without it. :P

> If you don't already know: the D gc NEVER collects objects until you run
> out of memory.  That's when it does a collection.  One suggestion is to
> make a very low-priority thread that runs in the background, calling
> 'std.gc.fullCollect()' over and over again to keep your memory profile
> from growing too large.

Ok. I'd interpreted "It is not predictable when a collection gets run, 
so the program can arbitrarily pause" (from 
http://www.digitalmars.com/d/garbage.html) as meaning that it could just 
'decide' to kick in upon any operation that allocates memory, even if 
you weren't running low.

 From the same page: "All threads other than the collector thread must 
be halted while the collection is in progress."
That seems a little worrying. Wouldn't this mean that running it in a 
low-priority thread wouldn't actually achieve much for a game? i.e. if 
the GC decides it wants to do some huge cleanup, then there's still no 
way to have it broken down, since the GC thread won't relinquish control 
until it's done?

Do you know if generational garbage collection using genCollect() would 
help, or is this just as likely to be arbitrarily 'greedy' for time? If 
not, is there an ideal solution for incremental garbage collection that 
could be built into D, or would this kill the GC's effectiveness completely?

> One idea I once had was to keep an eye on the amount of memory your game
> is using.  At start up, compute (MaxMemory - CurrentlyUsedMemory).  If
> you're using between 0% - 20% of that, don't bother collecting.  If
> you're using 20% - 40%, run a very-low priority background collect.  If
> you get to 40% - 60%, run a higher-priority collect, etc.
> 
> That way, the time spent running collections is proportional to how much
> memory you're using.  The cost of running the GC is amortized over time,
> instead of being in one great big lump [2].

Ok, re-thinking my above comment: does this mean that by continually 
forcing a full collection in a low-priority thread I could guarantee 
that individual garbage collections aren't going to take long? If so, 
wouldn't it then be feasible to force it constantly (every frame of the 
game) in my main thread anyway?

[noted, snipped]

> 
> Anyway, I hope this has helped, or at least given you some ideas.  Since
> I'm still learning D myself, take all of the above with a grain or two
> of salt.
> 

Ok, I'll keep that in mind. I've even had the audacity to question some 
of your advice above! ;)

Thanks for all your help; I appreciate your time, and sympathize with 
your blue-screen nightmares! :P



More information about the Digitalmars-d mailing list