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).

Reply via email to