On Monday, 4 January 2016 at 09:13:25 UTC, Jonathan M Davis wrote:
On Monday, January 04, 2016 07:30:50 aki via
Digitalmars-d-learn wrote:
But wait, how does GC detect there still be a live reference to
the object Foo?
Because store is just a fix sized array of bytes.
ubyte[size] store;
GC cannot be aware of the reference, right?
As I understand it, the GC doesn't actually care about whether
something is a pointer when it tries to figure out whether
something refers to something - or at least, it'll treat
integers as if they were pointers so that if you tried to do
something like
size_t i;
{
auto p = new int(5);
i = cast(size_t)p;
}
// GC will not collect p even if it runs now
then the fact that i matches the value of the address that p
points to is enough for the GC to not collect the memory
pointed to by p, even if there are no longer any pointers
referring to it. This prevents problems when you do stuff like
cast pointers to integers to store their values (which normally
is crazy but on rare occasions makes sense). The downside is
that the GC then has to treat all integers as if they were
pointers, so if you have an integer whose value happens to
match that of a memory address in GC-allocated memory (a so
called false pointer), then that memory won't be freed, even if
nothing is really pointing to it anymore. Fortunately, however,
false pointers are primarily limited to 32-bit programs, and
64-bit programs don't have that problem because of how large
their address space is (but 32-bit programs which allocate most
of their address space can definitely run into problems where
memory that should be freed isn't thanks to false pointers).
- Jonathan M Davis
That's only because we don't have a precise garbage collector and
can't be relied upon. It's more of a bug / limitation rather than
something to actually use.
In the case of std.variant, it's not just byte[size] store, it's
actually a union:
union
{
ubyte[size] store;
// conservatively mark the region as pointers
static if (size >= (void*).sizeof)
void*[size / (void*).sizeof] p;
}
Which tells the garbage collector that it may be pointers there,
making it valid even for precise garbage collectors (which would
have to conservatively handle such a union).