Discussion:
Understanding the GC
(too old to reply)
Jeremy DeHaan
2013-01-30 06:00:42 UTC
Permalink
I've been reading TDPL book and was also reading some posts on
these forums about the GC, but I wanted to clarify a few things
to make sure I am understanding correctly.

From what I understand, when an object is recovered by the GC,
the destructor may or may not be called. Why is that? Is it for
performace reasons? What about the destructors of objects that
the original object contained? Are they called when the item
finally get's taken care of by the GC, or when the object is
originally recovered by the GC?

My other question is, at the end of the program will GC go
through every object it knows still holds memory and call their
destructors? My guess is that it does so that the GC ensures all
memory is successfully released before the program ends. I just
want to make sure since in http://dlang.org/class.html, it says,
"The garbage collector is not guaranteed to run the destructor
for all unreferenced objects." What exactly is an unreferenced
object?

Some other questions:

At what point is the GC called to do it's thing while the program
is running? Is it at certain intervals or is it when the
program's memory reaches a certain point?



Thanks very much for all the help!
Mike Parker
2013-01-30 08:15:14 UTC
Permalink
On Wednesday, 30 January 2013 at 06:00:44 UTC, Jeremy DeHaan
Post by Jeremy DeHaan
From what I understand, when an object is recovered by the GC,
the destructor may or may not be called. Why is that? Is it for
That's not quite correct. When the object is collected, its
destructor will be called. But you have no control over when or
if it will happen during runtime. More on this below in relation
to your question about unreferenced objects.
Post by Jeremy DeHaan
performace reasons? What about the destructors of objects that
the original object contained? Are they called when the item
finally get's taken care of by the GC, or when the object is
originally recovered by the GC?
Destructors of members will not be called when an object is
collected. Only that of the object itself. But, there's no
guarantee that any member references will still be valid when the
object's destructor is called. See below for more.
Post by Jeremy DeHaan
My other question is, at the end of the program will GC go
through every object it knows still holds memory and call their
destructors? My guess is that it does so that the GC ensures
Yes.
Post by Jeremy DeHaan
all memory is successfully released before the program ends. I
just want to make sure since in http://dlang.org/class.html, it
says, "The garbage collector is not guaranteed to run the
destructor for all unreferenced objects." What exactly is an
unreferenced object?
A "referenced" object is one that is still in use by the program.
Example:

auto mc = new MyClass;

// Here, there is exactly one reference to the MyClass instance
// and it is still active.

// But if i do this...
auto mc2 = mc;

// Now there are 2 references to the same instance.
// Set one to null.
mc = null;

// Now there is only one reference. Null it...
mc2 = null;

// Now all references to the original instance are invalid,
// so the object is unreachable by the program, so it is an
// unreferenced object.

The GC can only collect objects that it can be sure are
unreferenced. Sometimes it can't be sure, in which case that
particular object won't be collected during run time. For the
objects that are determined to be collectable, there's no way to
guarantee that any one of them will be collected in any given
collection cycle. Because of that, you cannot rely on the order
of destruction. Consider:

class Foo {}
class Bar { Foo f; }

Bar b = new Bar;
b.f = new Foo;

Given that b.f is the only reference to this Foo instance, then
this instance of Foo will become unreferenced at the same time
that the instance of Bar does. But, again, we cannot rely on the
Bar instance being collected and destructed before the Foo
instance. So if you have a Bar destructor that tries to access a
member in f, then you would get a crash some of the time. Worse,
what if there were more references to the Foo instance outside of
Bar that haven't been released yet? If you tried to destroy f
from the Bar destructor, or perhaps call some sort of cleanup
method to release system resources that f controls, you'll get a
crash somewhere else in the program when another bit of code
tries to access the no longer valid reference. That would likely
be a marathon debugging session, because most of the time you
don't expect that sort of thing.
Post by Jeremy DeHaan
At what point is the GC called to do it's thing while the
program is running? Is it at certain intervals or is it when
the program's memory reaches a certain point?
My understanding is that the current implementation only runs
collections when memory is allocated. Meaning, when you allocate
a new object instance, or cause memory to be allocated via some
built-in operations (on arrays, for example), the GC will check
if anything needs to be collected and will do it at that time. I
don't know if it's run on every allocation, or only when certain
criteria or met, and I really don't care. That's an
implementation detail. The D language itself does not specify any
of that.
Mike Parker
2013-01-30 08:21:53 UTC
Permalink
The take-home point of all of this is that you shouldn't rely on
destructors for resource deallocation. You could do it in by
manually destructing objects when you are finished with them (via
the destroy() method), but then you have to be extra careful
about class members, ownership, order of destruction, and all of
that. I find that it's much simpler if I give each of my objects
a specific cleanup method that releases its own resources. When
an object is no longer needed, I call its cleanup method and
clear any references to it. This ensures that system resources or
whatever are released in a predictable order and I don't run into
odd crashes from trying to release something that's no longer
valid. The GC takes care of the rest.
monarch_dodra
2013-01-30 10:29:25 UTC
Permalink
Post by Mike Parker
On Wednesday, 30 January 2013 at 06:00:44 UTC, Jeremy DeHaan
Post by Jeremy DeHaan
From what I understand, when an object is recovered by the GC,
the destructor may or may not be called. Why is that? Is it for
That's not quite correct. When the object is collected, its
destructor will be called. But you have no control over when or
if it will happen during runtime. More on this below in
relation to your question about unreferenced objects.
To add to that, you also have to keep in mind that when the
program terminates (even legally), instead of running a *full*
collect cycle, the program just leaves, and lets the OS clear any
allocated memory. This is both faster, and safer.

What this means is that while there is a guarantee that
"collection=>destruction", there is no guarantee that actual
collection will happen.

If you absolutely must be sure that something allocated gets
*destroyed*, either destroy it yourself via an explicit call, or
bind it to a stack based RAII scheme, possibly with reference
counting.
Post by Mike Parker
Post by Jeremy DeHaan
performace reasons? What about the destructors of objects that
the original object contained? Are they called when the item
finally get's taken care of by the GC, or when the object is
originally recovered by the GC?
Destructors of members will not be called when an object is
collected. Only that of the object itself. But, there's no
guarantee that any member references will still be valid when
the object's destructor is called. See below for more.
Just to be clear, I suppose you (both) are talking about "member
references"? EG: Nested classes?

Destroying an object 100% guarantees its member destroyers are
also called, outer to inner, first in first out, as part of the
destruction process. The thing is that when you store a "class
reference" then you call the destructor of the reference itself.
References being glorified pointers, it basically means it does
nothing.

//----
struct S{}
class A{}

struct/class SA
{
S s; //destroying this means ~S gets called.
A a; //"destroying" this means doing "a = null".
}
Maxim Fomin
2013-01-30 11:57:00 UTC
Permalink
On Wednesday, 30 January 2013 at 10:29:26 UTC, monarch_dodra
On Wednesday, 30 January 2013 at 08:15:15 UTC, Mike Parker
Post by Mike Parker
Destructors of members will not be called when an object is
collected. Only that of the object itself. But, there's no
guarantee that any member references will still be valid when
the object's destructor is called. See below for more.
Just to be clear, I suppose you (both) are talking about
"member references"? EG: Nested classes?
I found calling member class references as nested classes
confusing - they are very different.
Destroying an object 100% guarantees its member destroyers are
also called, outer to inner, first in first out, as part of the
destruction process. The thing is that when you store a "class
reference" then you call the destructor of the reference
itself. References being glorified pointers, it basically means
it does nothing.
Are you implying that in following code snippet:

class A { ~this() { ... } }
class B { A a; ~this() { ... } }

destructor of A will be always called after B, so "a" member is
always accessible in B's dtor?
monarch_dodra
2013-01-30 12:08:06 UTC
Permalink
Post by Maxim Fomin
On Wednesday, 30 January 2013 at 10:29:26 UTC, monarch_dodra
On Wednesday, 30 January 2013 at 08:15:15 UTC, Mike Parker
Post by Mike Parker
Destructors of members will not be called when an object is
collected. Only that of the object itself. But, there's no
guarantee that any member references will still be valid when
the object's destructor is called. See below for more.
Just to be clear, I suppose you (both) are talking about
"member references"? EG: Nested classes?
I found calling member class references as nested classes
confusing - they are very different.
Destroying an object 100% guarantees its member destroyers are
also called, outer to inner, first in first out, as part of
the destruction process. The thing is that when you store a
"class reference" then you call the destructor of the
reference itself. References being glorified pointers, it
basically means it does nothing.
class A { ~this() { ... } }
class B { A a; ~this() { ... } }
destructor of A will be always called after B, so "a" member is
always accessible in B's dtor?
No. What gave you that idea? I said the "reference" a will be
destroyed (set to null). The actual referenced "class instance"
may or may not be destroyed by then. The class instance of A
itself is not a member of B.
Maxim Fomin
2013-01-30 12:17:32 UTC
Permalink
On Wednesday, 30 January 2013 at 12:08:07 UTC, monarch_dodra
On Wednesday, 30 January 2013 at 11:57:01 UTC, Maxim Fomin
Post by Maxim Fomin
On Wednesday, 30 January 2013 at 10:29:26 UTC, monarch_dodra
On Wednesday, 30 January 2013 at 08:15:15 UTC, Mike Parker
Post by Mike Parker
Destructors of members will not be called when an object is
collected. Only that of the object itself. But, there's no
guarantee that any member references will still be valid
when the object's destructor is called. See below for more.
Just to be clear, I suppose you (both) are talking about
"member references"? EG: Nested classes?
I found calling member class references as nested classes
confusing - they are very different.
Destroying an object 100% guarantees its member destroyers
are also called, outer to inner, first in first out, as part
of the destruction process. The thing is that when you store
a "class reference" then you call the destructor of the
reference itself. References being glorified pointers, it
basically means it does nothing.
class A { ~this() { ... } }
class B { A a; ~this() { ... } }
destructor of A will be always called after B, so "a" member
is always accessible in B's dtor?
No. What gave you that idea? I said the "reference" a will be
destroyed (set to null). The actual referenced "class instance"
may or may not be destroyed by then. The class instance of A
itself is not a member of B.
English is not native for me. Sometimes non-natives misunderstand
the meaning of the words.
monarch_dodra
2013-01-30 12:28:33 UTC
Permalink
Post by Maxim Fomin
English is not native for me. Sometimes non-natives
misunderstand the meaning of the words.
My apologies.
Jeremy DeHaan
2013-01-31 23:27:59 UTC
Permalink
On Wednesday, 30 January 2013 at 10:29:26 UTC, monarch_dodra
Post by monarch_dodra
To add to that, you also have to keep in mind that when the
program terminates (even legally), instead of running a *full*
collect cycle, the program just leaves, and lets the OS clear
any allocated memory. This is both faster, and safer.
What this means is that while there is a guarantee that
"collection=>destruction", there is no guarantee that actual
collection will happen.
If you absolutely must be sure that something allocated gets
*destroyed*, either destroy it yourself via an explicit call,
or bind it to a stack based RAII scheme, possibly with
reference counting.
So there is no guarantee at all that a destructor will be called
even at the end of the program? Because there is an example in
the book using a class destructor to free allocated data.



I definitely understand now about how not to rely on a destructor
to free up memory during runtime, but it seems counterintuitive
to have the ability to write a destructor with no guarantee it
would ever be called even at cleanup.
Steven Schveighoffer
2013-01-31 23:53:27 UTC
Permalink
On Thu, 31 Jan 2013 18:27:59 -0500, Jeremy DeHaan
To add to that, you also have to keep in mind that when the program
terminates (even legally), instead of running a *full* collect cycle,
the program just leaves, and lets the OS clear any allocated memory.
This is both faster, and safer.
What this means is that while there is a guarantee that
"collection=>destruction", there is no guarantee that actual collection
will happen.
If you absolutely must be sure that something allocated gets
*destroyed*, either destroy it yourself via an explicit call, or bind
it to a stack based RAII scheme, possibly with reference counting.
So there is no guarantee at all that a destructor will be called even at
the end of the program? Because there is an example in the book using a
class destructor to free allocated data.
I'm pretty sure all GCs do not have a guarantee of running all
destructors. I think D's GC makes a good effort to do so.
I definitely understand now about how not to rely on a destructor to
free up memory during runtime, but it seems counterintuitive to have
the ability to write a destructor with no guarantee it would ever be
called even at cleanup.
A destructor should ONLY be used to free up resources other than GC
allocated memory. Because of that, it's generally not used.

It should be used almost as a "last resort".

For example, a class that holds a file descriptor should have both a
destructor (which closes the descriptor) and a manual close method. The
former is to clean up the file descriptor in case nobody thought to close
it manually before all references were gone, and the latter is because
file descriptors are not really managed by the GC, and so should be
cleaned up when they are no longer used.

This kind of gives us a paradox, since the class is managed via the GC,
how do you know it's no longer used (that is, how do you know this is the
last reference to it)? That is really up to the application design. But
I wouldn't recommend relying on the GC to clean up your descriptors.

-Steve
Jeremy DeHaan
2013-02-01 03:57:16 UTC
Permalink
On Thursday, 31 January 2013 at 23:53:26 UTC, Steven
Post by Steven Schveighoffer
On Thu, 31 Jan 2013 18:27:59 -0500, Jeremy DeHaan
Post by Maxim Fomin
On Wednesday, 30 January 2013 at 10:29:26 UTC, monarch_dodra
Post by monarch_dodra
To add to that, you also have to keep in mind that when the
program terminates (even legally), instead of running a
*full* collect cycle, the program just leaves, and lets the
OS clear any allocated memory. This is both faster, and safer.
What this means is that while there is a guarantee that
"collection=>destruction", there is no guarantee that actual
collection will happen.
If you absolutely must be sure that something allocated gets
*destroyed*, either destroy it yourself via an explicit call,
or bind it to a stack based RAII scheme, possibly with
reference counting.
So there is no guarantee at all that a destructor will be
called even at the end of the program? Because there is an
example in the book using a class destructor to free allocated
data.
I'm pretty sure all GCs do not have a guarantee of running all
destructors. I think D's GC makes a good effort to do so.
Post by Maxim Fomin
I definitely understand now about how not to rely on a
destructor to free up memory during runtime, but it seems
counterintuitive to have the ability to write a destructor
with no guarantee it would ever be called even at cleanup.
A destructor should ONLY be used to free up resources other
than GC allocated memory. Because of that, it's generally not
used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have
both a destructor (which closes the descriptor) and a manual
close method. The former is to clean up the file descriptor in
case nobody thought to close it manually before all references
were gone, and the latter is because file descriptors are not
really managed by the GC, and so should be cleaned up when they
are no longer used.
This kind of gives us a paradox, since the class is managed via
the GC, how do you know it's no longer used (that is, how do
you know this is the last reference to it)? That is really up
to the application design. But I wouldn't recommend relying on
the GC to clean up your descriptors.
-Steve
This makes a whole lot of sense to me. I never realized that a GC
could be imperfect in this regard. I also don't know much about
GC design and implementation, but that was the purpose of this
thread!

I definitely like the idea of having a manual way of cleaning up
and a destructor as a back up for times such as these.

Thanks for all the help guys! I learned a lot!
monarch_dodra
2013-02-01 07:07:00 UTC
Permalink
On Thursday, 31 January 2013 at 23:53:26 UTC, Steven
Post by Steven Schveighoffer
A destructor should ONLY be used to free up resources other
than GC allocated memory. Because of that, it's generally not
used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have
both a destructor (which closes the descriptor) and a manual
close method. The former is to clean up the file descriptor in
case nobody thought to close it manually before all references
were gone, and the latter is because file descriptors are not
really managed by the GC, and so should be cleaned up when they
are no longer used.
This kind of gives us a paradox, since the class is managed via
the GC, how do you know it's no longer used (that is, how do
you know this is the last reference to it)? That is really up
to the application design. But I wouldn't recommend relying on
the GC to clean up your descriptors.
-Steve
I've actually run into this very issue: I was iterating on files,
opening them, and placing the descriptor in GC-allocated RAII
data. I can't remember if class or struct, but not a big issue.
Come to think about it, I think I was using "File", but
allocating them because I thought they were classes `auto f = new
File("my file", "r")`.

After running for a second, my program halts, because an
exception was thrown trying to open a new file:
"Cannot open file: Too many open file handles".

It was basically: Sure, the GC will destroy and close files for
you... if you forget... eventually...

I ended up closing them in scope(exit) blocks. Problem
immediately solved. Or I could have stopped allocating my File's
on the heap.

Either way, it shows you shouldn't rely on the GC for
deterministic destruction.
Steven Schveighoffer
2013-02-01 15:37:25 UTC
Permalink
Post by monarch_dodra
Post by Steven Schveighoffer
A destructor should ONLY be used to free up resources other than GC
allocated memory. Because of that, it's generally not used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have both a
destructor (which closes the descriptor) and a manual close method.
The former is to clean up the file descriptor in case nobody thought to
close it manually before all references were gone, and the latter is
because file descriptors are not really managed by the GC, and so
should be cleaned up when they are no longer used.
This kind of gives us a paradox, since the class is managed via the GC,
how do you know it's no longer used (that is, how do you know this is
the last reference to it)? That is really up to the application
design. But I wouldn't recommend relying on the GC to clean up your
descriptors.
-Steve
I've actually run into this very issue: I was iterating on files,
opening them, and placing the descriptor in GC-allocated RAII data. I
can't remember if class or struct, but not a big issue. Come to think
about it, I think I was using "File", but allocating them because I
thought they were classes `auto f = new File("my file", "r")`.
After running for a second, my program halts, because an exception was
"Cannot open file: Too many open file handles".
It was basically: Sure, the GC will destroy and close files for you...
if you forget... eventually...
I ended up closing them in scope(exit) blocks. Problem immediately
solved. Or I could have stopped allocating my File's on the heap.
Either way, it shows you shouldn't rely on the GC for deterministic
destruction.
Actually, that's a different problem. File is a struct, and structs do
NOT have their destructor run by the GC. Only Objects do.

This is a GC limitation, since structs do not contain a pointer to their
typeinfo like classes do, and there is no provision for storing a pointer
to the typeinfo of a block. It could be fixed by a more precise GC.
AIUI, we have something like that coming, but I've been hearing that for
more than a year ;)

-Steve
monarch_dodra
2013-02-01 15:46:11 UTC
Permalink
On Friday, 1 February 2013 at 15:37:25 UTC, Steven Schveighoffer
On Fri, 01 Feb 2013 02:07:00 -0500, monarch_dodra
Post by Jeremy DeHaan
On Thursday, 31 January 2013 at 23:53:26 UTC, Steven
Post by Steven Schveighoffer
A destructor should ONLY be used to free up resources other
than GC allocated memory. Because of that, it's generally
not used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have
both a destructor (which closes the descriptor) and a manual
close method. The former is to clean up the file descriptor
in case nobody thought to close it manually before all
references were gone, and the latter is because file
descriptors are not really managed by the GC, and so should
be cleaned up when they are no longer used.
This kind of gives us a paradox, since the class is managed
via the GC, how do you know it's no longer used (that is, how
do you know this is the last reference to it)? That is
really up to the application design. But I wouldn't
recommend relying on the GC to clean up your descriptors.
-Steve
I've actually run into this very issue: I was iterating on
files, opening them, and placing the descriptor in
GC-allocated RAII data. I can't remember if class or struct,
but not a big issue. Come to think about it, I think I was
using "File", but allocating them because I thought they were
classes `auto f = new File("my file", "r")`.
After running for a second, my program halts, because an
"Cannot open file: Too many open file handles".
It was basically: Sure, the GC will destroy and close files
for you... if you forget... eventually...
I ended up closing them in scope(exit) blocks. Problem
immediately solved. Or I could have stopped allocating my
File's on the heap.
Either way, it shows you shouldn't rely on the GC for
deterministic destruction.
Actually, that's a different problem. File is a struct, and
structs do NOT have their destructor run by the GC. Only
Objects do.
This is a GC limitation, since structs do not contain a pointer
to their typeinfo like classes do, and there is no provision
for storing a pointer to the typeinfo of a block. It could be
fixed by a more precise GC. AIUI, we have something like that
coming, but I've been hearing that for more than a year ;)
-Steve
Oh. Wow. That's news to me.

I'd say as long as you don't new your structs, you are fine, but
apparently, dynamic arrays don't clean up after themselves either
(!) That's a whole other ballgame...

That's quite scary. It brings back into question a few of my
implementations...
Steven Schveighoffer
2013-02-01 18:41:04 UTC
Permalink
Post by monarch_dodra
Post by Steven Schveighoffer
This is a GC limitation, since structs do not contain a pointer to
their typeinfo like classes do, and there is no provision for storing a
pointer to the typeinfo of a block. It could be fixed by a more
precise GC. AIUI, we have something like that coming, but I've been
hearing that for more than a year ;)
-Steve
Oh. Wow. That's news to me.
I'd say as long as you don't new your structs, you are fine, but
apparently, dynamic arrays don't clean up after themselves either (!)
That's a whole other ballgame...
Dynamic arrays do clean up the array memory. For arrays of objects, or
arrays of structs that have only GC-based resources, those items are also
individually cleaned up by the GC. But if you had, for instance, an array
of self-closing file descriptor structs, those would NOT be cleaned up by
the GC.
Post by monarch_dodra
That's quite scary. It brings back into question a few of my
implementations...
People should definitely be aware of this limitation. It usually is not
of any concern because it is rare to have a struct that has a non-GC
reference on the heap. But it is something to be aware of.

Note that if your struct is a *member* of a class, it's destructor will be
called because it's destructor is called as part of the object's
destructor. But this isn't always what you want!

I think people have been harping on this limitation of File (and
reference-counted structs in general) for a long time. There is a
bugzilla issue for it somewhere.

-Steve

FG
2013-02-01 17:41:47 UTC
Permalink
Actually, that's a different problem. File is a struct, and structs do NOT have
their destructor run by the GC. Only Objects do.
This is a GC limitation, since structs do not contain a pointer to their
typeinfo like classes do, and there is no provision for storing a pointer to the
typeinfo of a block. It could be fixed by a more precise GC. AIUI, we have
something like that coming, but I've been hearing that for more than a year ;)
So currently the only way to make a struct's destructor work when the struct is
on the heap is to encapsulate that struct in a class?
I have tested the following:

struct A { ... }
class C { A a; ... }

A a = A(); // OK
A *b = new A(); // BAD, no finalization
C c = new C(); // OK, a's destructor will be called
Sean Kelly
2013-02-01 15:30:08 UTC
Permalink
A destructor should ONLY be used to free up resources other than GC allocated memory. Because of that, it's generally not used.
It should be used almost as a "last resort".
For example, a class that holds a file descriptor should have both a destructor (which closes the descriptor) and a manual close method. The former is to clean up the file descriptor in case nobody thought to close it manually before all references were gone, and the latter is because file descriptors are not really managed by the GC, and so should be cleaned up when they are no longer used.
This kind of gives us a paradox, since the class is managed via the GC, how do you know it's no longer used (that is, how do you know this is the last reference to it)? That is really up to the application design. But I wouldn't recommend relying on the GC to clean up your descriptors.
-Steve
I've actually run into this very issue: I was iterating on files, opening them, and placing the descriptor in GC-allocated RAII data. I can't remember if class or struct, but not a big issue. Come to think about it, I think I was using "File", but allocating them because I thought they were classes `auto f = new File("my file", "r")`.
"Cannot open file: Too many open file handles".
It was basically: Sure, the GC will destroy and close files for you... if you forget... eventually...
I ended up closing them in scope(exit) blocks. Problem immediately solved. Or I could have stopped allocating my File's on the heap.
Either way, it shows you shouldn't rely on the GC for deterministic destruction.
The GC currently doesn't finalize structs, only classes. So that's an issue as well.
Steven Schveighoffer
2013-01-31 15:12:13 UTC
Permalink
Post by Mike Parker
My understanding is that the current implementation only runs
collections when memory is allocated. Meaning, when you allocate a new
object instance, or cause memory to be allocated via some built-in
operations (on arrays, for example), the GC will check if anything needs
to be collected and will do it at that time. I don't know if it's run on
every allocation, or only when certain criteria or met, and I really
don't care. That's an implementation detail. The D language itself does
not specify any of that.
This isn't quite accurate.

The GC first checks to see if there is a free block that would satisfy the
allocation, and if it can't find one, THEN it runs a collection cycle, and
if then it cannot allocate the block from any memory regained, it then
asks for more memory from the OS.

This can lead to the collection cycle running quite a bit when allocating
lots of data. I don't know if there are any measures to mitigate that,
but there probably should be.

-Steve
Sean Kelly
2013-01-31 16:28:59 UTC
Permalink
GG.reserve can be handy for this. It tells the GC to pre allocate a block of memory from the OS.
Post by Steven Schveighoffer
My understanding is that the current implementation only runs collections when memory is allocated. Meaning, when you allocate a new object instance, or cause memory to be allocated via some built-in operations (on arrays, for example), the GC will check if anything needs to be collected and will do it at that time. I don't know if it's run on every allocation, or only when certain criteria or met, and I really don't care. That's an implementation detail. The D language itself does not specify any of that.
This isn't quite accurate.
The GC first checks to see if there is a free block that would satisfy the allocation, and if it can't find one, THEN it runs a collection cycle, and if then it cannot allocate the block from any memory regained, it then asks for more memory from the OS.
This can lead to the collection cycle running quite a bit when allocating lots of data. I don't know if there are any measures to mitigate that, but there probably should be.
-Steve
Continue reading on narkive:
Loading...