Now all the GC has to do is to look at all the static variables and the "virtual stack", and call Mark() on all variables derived from VirtualObject that are not null.

This means that you know where the references to the objects are. If you know this then you can simply update the references when the objects move. An additional level of indirection is not required and it's not efficient anyway.