A bug in my code
Sergey Gromov
snake.scaly at gmail.com
Mon Sep 8 03:37:35 PDT 2008
bearophile <bearophileHUGS at lycos.com> wrote:
> So I have tried this, I have written this assuming that addRoot() adds
> a single pointer to the GC collected pool, but this last solution
> doesn't work, I don't know why:
> auto new_block = cast(Block*)mem_alloc(Block.sizeof);
> new_block.data = cast(int*)mem_alloc(nints * int.sizeof);
> new_block.len = nints;
> new_block.next = null;
> addRoot(new_block.next);
> addRoot(new_block.data);
What you do here is add two roots to GC: null and a pointer to your
ints. While the latter is relatively valid, the former is obviously
wrong: you tell GC to never collect a memory block which includes an
address of 0. What happens next is a) whatever you assign to block.next
is not kept alive by block since the .next field itself is not checked
for pointers; and b) if you ever change .data the old block will live
forever while the new one will not be referenced for the same reason as
a).
Here are the possible solutions. Note that they are independent, you
need to implement only one of them to make your code work.
1. Replace Block.next with
private Block* _next;
Block* next() {return _next;}
Block* next(Block* other) {
removeRoot(_next);
_next = other;
addRoot(_next);
return _next;
}
2. Replace
addRoot(new_block.next);
addRoot(new_block.data);
with
addRange(&new_block.next, &new_block.data+1);
which will make GC scan Block.next and Block.data for pointers on every
collection cycle, therefore automatically picking any changes to these
pointers.
Both changes make your code work. Both require Block.~this() to remove
any unneeded roots or ranges, since they are permanent by their nature
and will keep any pointed memory allocated until the process terminates.
More information about the Digitalmars-d-learn
mailing list