www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Does the GC ever perform a generational collect?

reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
As I'm planning on writing some kind of game in D, the issue of GC speed is 
coming up.  The manual says that the time it takes for the GC to run is 
unbounded; thus, it's best to do as much as you can for setup, before the 
speed-critical game loop.  What I'm wondering, however, is how I can avoid 
having the GC perform a fullCollect() as much as possible, as the game will 
nonetheless be creating and destroying objects constantly throughout the 
loop.

I'm wondering if the GC performs generational (smaller) collections 
automatically.  If so, then I suppose I don't have much to worry about, as 
the fullCollect() will probably be run very seldom, if ever.  If not, well.. 
I guess that means I have to call it.  And I don't know when to. 
Mar 05 2005
next sibling parent reply h3r3tic <foo bar.baz> writes:
Jarrett Billingsley wrote:
 As I'm planning on writing some kind of game in D, the issue of GC speed is 
 coming up.  The manual says that the time it takes for the GC to run is 
 unbounded; thus, it's best to do as much as you can for setup, before the 
 speed-critical game loop.  What I'm wondering, however, is how I can avoid 
 having the GC perform a fullCollect() as much as possible, as the game will 
 nonetheless be creating and destroying objects constantly throughout the 
 loop.

<my2cents> In my programs, I call gc.fullCollect() after the setup code but at realtime, I try not to allocate anything - that's a general rule for any programming language. In the game industry ppl will generally tell you to use custom memory allocators, mem pools and such because if the gc stalls won't kill you, memory fragmentation will. If the game is creating and destroying objects all the time, you might consider not really destroying them, but putting them back onto a "free list" instead. Marking them as unused but not deleting. Then when a new object is requested, you'd take it from the list again without dynamically allocating any memory. </my2cents>
Mar 05 2005
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
 If the game is creating and destroying objects all the time, you might 
 consider not really destroying them, but putting them back onto a "free 
 list" instead. Marking them as unused but not deleting. Then when a new 
 object is requested, you'd take it from the list again without dynamically 
 allocating any memory.

Free lists sound like a good idea. And inheriting from a template would probably make them very easy to implement indeed. Thank you :) Though the question still stands - does the GC in fact run generational collection cycles throughout the program, or is that function there entirely for our own use?
Mar 05 2005
parent reply "Walter" <newshound digitalmars.com> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message
news:d0dftv$1na7$1 digitaldaemon.com...
 Though the question still stands - does the GC in fact run generational
 collection cycles throughout the program, or is that function there

 for our own use?

It currently does not, however, D's design will allow for a future generational collector to be retrofitted. Also, the gc will only run a collect during an allocation. If your program isn't allocating, it won't be collecting. Furthermore, malloc() also has unbounded time.
Mar 06 2005
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
 It currently does not, however, D's design will allow for a future
 generational collector to be retrofitted. Also, the gc will only run a
 collect during an allocation. If your program isn't allocating, it won't 
 be
 collecting.

Ah, thanks for that :)
Mar 07 2005
prev sibling parent reply "Charlie Patterson" <charliep1 excite.com> writes:
"h3r3tic" <foo bar.baz> wrote in message 
news:d0ddqc$1ljj$1 digitaldaemon.com...
 <my2cents>
 In my programs, I call gc.fullCollect() after the setup code but at 
 realtime, I try not to allocate anything - that's a general rule for any 
 programming language. In the game industry ppl will generally tell you to 
 use custom memory allocators, mem pools and such because if the gc stalls 
 won't kill you, memory fragmentation will. If the game is creating and 
 destroying objects all the time, you might consider not really destroying 
 them, but putting them back onto a "free list" instead. Marking them as 
 unused but not deleting. Then when a new object is requested, you'd take 
 it from the list again without dynamically allocating any memory.
 </my2cents>

I assumed this was written with a hint of irony, but no one else seemed to bite. (-: So you start with a GC, then you hoard memory to save it from the GC and create a "free list." Then, you are very careful not to allocate anything so the GC won't kick in. This effectively creates a non-GC, "old school" program in a GC language by having the discipline to work around the GC (tricky in groups of programmer's at various levels of experience). You end up with the overhead without the benefits. I realize you have to do this since there are no guarantees on timings, but certainly some <grins> and smileys are appropriate? It sounds like the answer should be to avoid D and use C or C++! Think about it! Any of the features you think are better in D are probably tied to the GC (such as slices). As long as you have to use discipline, stick to being disciplined in C++ and not using too many operator overloads or lattice-style multiple inheritance. I thought D did have a delete operator, and I assumed this would immediately do the deletion instead of just ignoring the call. But I haven't seen any one mention this, so maybe not.
Mar 08 2005
next sibling parent "Walter" <newshound digitalmars.com> writes:
"Charlie Patterson" <charliep1 excite.com> wrote in message
news:d0kfrc$2lqs$1 digitaldaemon.com...
 I thought D did have a delete operator, and I assumed this would

 do the deletion instead of just ignoring the call.

That's exactly what it does.
Mar 08 2005
prev sibling next sibling parent reply "Unknown W. Brackets" <unknown simplemachines.org> writes:
You're quite the cynic, are you?

If you don't want the gc, turn it off.  This could cause your program to 
start drinking memory, but if you know what you're doing and you turn it 
back on when you can, you'll be fine.  No problems, no collects, all the 
memory you want, just don't forget to use delete.

This is really a lot like time slicing on any modern operating system. 
Unless you're running your software, dedicated, as an operating system 
on a computer with no other controlling software on it, you'll probably 
be hit harder by that...

Furthermore, you ignore the fact that malloc and everything else take 
time themselves... you can't do those in a loop either!  Do you not load 
all your resources before going into the program?  Or do you decompress 
your data on the fly?  Load graphics from disk during the most intensive 
loops?

That's nothing (largely) different from acquiring memory.

-[Unknown]


 I assumed this was written with a hint of irony, but no one else seemed to 
 bite.  (-:  So you start with a GC, then you hoard memory to save it from 
 the GC and create a "free list."  Then, you are very careful not to allocate 
 anything so the GC won't kick in.  This effectively creates a non-GC, "old 
 school" program in a GC language by having the discipline to work around the 
 GC (tricky in groups of programmer's at various levels of experience).  You 
 end up with the overhead without the benefits.
 
 I realize you have to do this since there are no guarantees on timings, but 
 certainly some <grins> and smileys are appropriate?
 
 It sounds like the answer should be to avoid D and use C or C++!  Think 
 about it!  Any of the features you think are better in D are probably tied 
 to the GC (such as slices).  As long as you have to use discipline, stick to 
 being disciplined in C++ and not using too many operator overloads or 
 lattice-style multiple inheritance.

Mar 08 2005
parent reply "Charlie Patterson" <charliep1 excite.com> writes:
"Unknown W. Brackets" <unknown simplemachines.org> wrote in message 
news:d0lor5$vt0$1 digitaldaemon.com...
 You're quite the cynic, are you?

I prefer practic. (-: I think that would mean a practical kinda dude.
 If you don't want the gc, turn it off.  This could cause your program to 
 start drinking memory, but if you know what you're doing and you turn it 
 back on when you can, you'll be fine.  No problems, no collects, all the 
 memory you want, just don't forget to use delete.

 Furthermore, you ignore the fact that malloc and everything else take time 
 themselves... you can't do those in a loop either!  Do you not load all 
 your resources before going into the program?  Or do you decompress your 
 data on the fly?  Load graphics from disk during the most intensive loops?

My point was that, if you are going to deny the GC, and link to a bunch of C libs for a video game, uh, use C (or simple C++). I'm all for higher-level languages whey they are practical, but it seems odd to carry the overhead of a garbage collector and then fight it. How helpful will it be when limited to initialization if you then have to avoid it and test for it's accidental use, etc. Again, I bring up the point of a team of varied skill levels. Worse, they have to understand the underlying language details and libraries to make sure they aren't creating slices, for instance.
Mar 09 2005
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Charlie Patterson wrote:
 My point was that, if you are going to deny the GC, and link to a bunch of C 
 libs for a video game, uh, use C (or simple C++).  I'm all for higher-level 
 languages whey they are practical, but it seems odd to carry the overhead of 
 a garbage collector and then fight it.  How helpful will it be when limited 
 to initialization if you then have to avoid it and test for it's accidental 
 use, etc.

You have a couple of solutions possible: * As others have noted, you don't have to turn off the gc forever. You can turn it back on and have it do a garbage collecting pass periodically. * You can implement your own garbage collector. The current collector is simply implemented in the Phobos library which comes with Walter's compiler. You can remove it and put in one of your own. In fact, there are a number of us who would be delighted to see somebody implement a generational collector and then release it publicly.
Mar 09 2005
prev sibling parent reply "Nick Sabalausky" <z a.a> writes:
"Charlie Patterson" <charliep1 excite.com> wrote in message 
news:d0kfrc$2lqs$1 digitaldaemon.com...
 "h3r3tic" <foo bar.baz> wrote in message 
 news:d0ddqc$1ljj$1 digitaldaemon.com...
 <my2cents>
 In my programs, I call gc.fullCollect() after the setup code but at 
 realtime, I try not to allocate anything - that's a general rule for any 
 programming language. In the game industry ppl will generally tell you to 
 use custom memory allocators, mem pools and such because if the gc stalls 
 won't kill you, memory fragmentation will. If the game is creating and 
 destroying objects all the time, you might consider not really destroying 
 them, but putting them back onto a "free list" instead. Marking them as 
 unused but not deleting. Then when a new object is requested, you'd take 
 it from the list again without dynamically allocating any memory.
 </my2cents>

I assumed this was written with a hint of irony, but no one else seemed to bite. (-: So you start with a GC, then you hoard memory to save it from the GC and create a "free list." Then, you are very careful not to allocate anything so the GC won't kick in. This effectively creates a non-GC, "old school" program in a GC language by having the discipline to work around the GC (tricky in groups of programmer's at various levels of experience). You end up with the overhead without the benefits. I realize you have to do this since there are no guarantees on timings, but certainly some <grins> and smileys are appropriate?

Aside from timing issues, the other benefit of free lists, as h3r3tic mentioned, is that it helps avoid memory fragmentation. While its not *as* much of an issue on PCs, fragmented memory is a problem that can wreak complete havoc on games running on a console system. And it's not just a matter of using/not using garbage collection. It hits just as hard when using C's malloc and free all over the place.
 It sounds like the answer should be to avoid D and use C or C++!  Think 
 about it!  Any of the features you think are better in D are probably tied 
 to the GC (such as slices).  As long as you have to use discipline, stick 
 to being disciplined in C++ and not using too many operator overloads or 
 lattice-style multiple inheritance.

 I thought D did have a delete operator, and I assumed this would 
 immediately do the deletion instead of just ignoring the call.  But I 
 haven't seen any one mention this, so maybe not.

 

Mar 09 2005
parent reply "Charlie Patterson" <charliep1 excite.com> writes:
"Nick Sabalausky" <z a.a> wrote in message 
news:d0muvr$29v2$1 digitaldaemon.com...

 Aside from timing issues, the other benefit of free lists, as h3r3tic 
 mentioned, is that it helps avoid memory fragmentation. While its not *as* 
 much of an issue on PCs, fragmented memory is a problem that can wreak 
 complete havoc on games running on a console system.

 And it's not just a matter of using/not using garbage collection. It hits 
 just as hard when using C's malloc and free all over the place.

I'm a fan of D, but this just pushes me farther away when writing games! Now you've reminded me that D has a built-in GC which uses a specific algorithm that isn't really the best for real-time needs. And unlike C++, I can't insert another memory management scheme and make it look natural, as in a new operator for a specific class so as to avoid fragmentation.
Mar 09 2005
parent reply =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Charlie Patterson wrote:

 Now you've reminded me that D has a built-in GC which uses a specific 
 algorithm that isn't really the best for real-time needs.  And unlike C++, I 
 can't insert another memory management scheme and make it look natural, as 
 in a new operator for a specific class so as to avoid fragmentation.

Why not ? http://www.digitalmars.com/d/class.html#allocators --anders
Mar 09 2005
parent reply "Charlie Patterson" <charliep1 excite.com> writes:
"Anders F Björklund" <afb algonet.se> wrote in message 
news:d0n77i$2jep$1 digitaldaemon.com...
 Charlie Patterson wrote:

 Now you've reminded me that D has a built-in GC which uses a specific 
 algorithm that isn't really the best for real-time needs.  And unlike 
 C++, I can't insert another memory management scheme and make it look 
 natural, as in a new operator for a specific class so as to avoid 
 fragmentation.

Why not ? http://www.digitalmars.com/d/class.html#allocators

Oh. (-: Does an "auto class" delete immediately upon leaving a scope? If that is the point, the docs could be slightly improved. I'm not sure what is being gotten at here.
Mar 09 2005
next sibling parent =?ISO-8859-1?Q?Anders_F_Bj=F6rklund?= <afb algonet.se> writes:
Charlie Patterson wrote:

Why not ? http://www.digitalmars.com/d/class.html#allocators

Oh. (-: Does an "auto class" delete immediately upon leaving a scope? If that is the point, the docs could be slightly improved. I'm not sure what is being gotten at here.

I think so: (?) http://www.digitalmars.com/d/attribute.html#auto
 For local declarations, auto implements the RAII (Resource Acquisition
 Is Initialization) protocol. This means that the destructor for an
 object is automatically called when the auto reference to it goes out of
 scope. The destructor is called even if the scope is exited via a thrown
 exception, thus auto is used to guarantee cleanup.

More stuff on http://www.digitalmars.com/d/memory.html#newdelete --anders
Mar 09 2005
prev sibling parent reply "Nick Sabalausky" <z a.a> writes:
"Charlie Patterson" <charliep1 excite.com> wrote in message 
news:d0n7vt$2koi$1 digitaldaemon.com...
 "Anders F Björklund" <afb algonet.se> wrote in message 
 news:d0n77i$2jep$1 digitaldaemon.com...
 Charlie Patterson wrote:

 Now you've reminded me that D has a built-in GC which uses a specific 
 algorithm that isn't really the best for real-time needs.  And unlike 
 C++, I can't insert another memory management scheme and make it look 
 natural, as in a new operator for a specific class so as to avoid 
 fragmentation.

Why not ? http://www.digitalmars.com/d/class.html#allocators

Oh. (-: Does an "auto class" delete immediately upon leaving a scope? If that is the point, the docs could be slightly improved. I'm not sure what is being gotten at here.

That's a good question. I'm unsure about that too. It says that the destructor is called when the "auto" object goes out of scope, but doesn't say anything about the deallocator. Maybe it's still just "whenever the GC gets around to it"? If so, then I guess using an auto class wouldn't help and you'd still have to explicitly delete whenever you want to make sure the memory is added back to the free list.
Mar 09 2005
parent Kris <Kris_member pathlink.com> writes:
In article <d0n9q0$2mjs$1 digitaldaemon.com>, Nick Sabalausky says...
"Charlie Patterson" <charliep1 excite.com> wrote in message 
news:d0n7vt$2koi$1 digitaldaemon.com...
 "Anders F Björklund" <afb algonet.se> wrote in message 
 news:d0n77i$2jep$1 digitaldaemon.com...
 Charlie Patterson wrote:

 Now you've reminded me that D has a built-in GC which uses a specific 
 algorithm that isn't really the best for real-time needs.  And unlike 
 C++, I can't insert another memory management scheme and make it look 
 natural, as in a new operator for a specific class so as to avoid 
 fragmentation.

Why not ? http://www.digitalmars.com/d/class.html#allocators

Oh. (-: Does an "auto class" delete immediately upon leaving a scope? If that is the point, the docs could be slightly improved. I'm not sure what is being gotten at here.

That's a good question. I'm unsure about that too. It says that the destructor is called when the "auto" object goes out of scope, but doesn't say anything about the deallocator. Maybe it's still just "whenever the GC gets around to it"? If so, then I guess using an auto class wouldn't help and you'd still have to explicitly delete whenever you want to make sure the memory is added back to the free list.

Use of 'auto' wraps the block with an implicit try/catch and, as far as I recall, inserts a 'delete' within the 'finally' clause. Take a look at the (dis)assembly to verify ... - Kris
Mar 09 2005
prev sibling parent reply Ben Hinkle <Ben_member pathlink.com> writes:
In article <d0d9ps$1hv8$1 digitaldaemon.com>, Jarrett Billingsley says...
As I'm planning on writing some kind of game in D, the issue of GC speed is 
coming up.  The manual says that the time it takes for the GC to run is 
unbounded; thus, it's best to do as much as you can for setup, before the 
speed-critical game loop.  What I'm wondering, however, is how I can avoid 
having the GC perform a fullCollect() as much as possible, as the game will 
nonetheless be creating and destroying objects constantly throughout the 
loop.

I'm wondering if the GC performs generational (smaller) collections 
automatically.  If so, then I suppose I don't have much to worry about, as 
the fullCollect() will probably be run very seldom, if ever.  If not, well.. 
I guess that means I have to call it.  And I don't know when to. 

The GC in dmd is not generational. When it collects it collects everything. I'm not sure what GC gdc uses. I think Sean is working on an interface to plug in different GC's but I'm not sure how far along that is. A while ago I hacked up phobos to use a generational Boehm GC but it wasn't thread-safe. It's not that hard to get another GC basically working since all you need to do is replace some calls from internal/gc/gc.d into internal/gc/gcx.d, IIRC. -Ben
Mar 05 2005
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
 The GC in dmd is not generational.

Ah. Then I take it these functions in std. gc are just stubs? /*********************************** * Run a generational garbage collection cycle. * Takes less time than a fullcollect(), but isn't * as effective. */ void genCollect(); void genCollectNoStack();
Mar 05 2005
parent reply Ben Hinkle <Ben_member pathlink.com> writes:
In article <d0duck$21ob$1 digitaldaemon.com>, Jarrett Billingsley says...
 The GC in dmd is not generational.

Ah. Then I take it these functions in std. gc are just stubs? /*********************************** * Run a generational garbage collection cycle. * Takes less time than a fullcollect(), but isn't * as effective. */ void genCollect(); void genCollectNoStack();

The code for genCollect in internal/gc/gcx.d calls "fullcollectshell", which means it does a full collection instead of a no-op. Or maybe the way to say it is that dmd is a generational collector with 1 generation :-)
Mar 05 2005
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
 The code for genCollect in internal/gc/gcx.d
 calls "fullcollectshell", which means it does a full collection instead of 
 a
 no-op.
 Or maybe the way to say it is that dmd is a generational collector with 1
 generation :-)

Haha :) I see now.
Mar 06 2005