.NET has a function called GC.KeepAlive(Object)
. Its sole purpose is to ensure the lifetime of the referenced object lasts until code flow reaches the call.
This is normally not necessary unless one is interoperating with native code.
I have a situation where I've got a graph of C++ objects accessed via JNI, where certain root objects need to be kept alive to keep the children alive. Both the root objects and the child objects have mirrors in JVM land. If the root object is collected and freed on the C++ side (by way of a SWIG-generated finalizer), however, the child objects will become invalid, since their C++ backing object will have been freed.
This can be solved by ensuring the local variables that root the object graph have a lifetime that exceeds the last use of a child object. So I need an idiomatic function that does nothing to an object, yet won't be optimized away or moved (e.g. hoisted out of a loop). That's what GC.KeepAlive(Object)
does in .NET.
What is the approximate equivalent in Java?
PS: some possibly illustrative code:
class Parent {
long ptr;
void finalize() { free(ptr); }
Child getChild() { return new Child(expensive_operation(ptr)); }
}
class Child {
long ptr;
void doStuff() { do_stuff(ptr); }
}
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
}
The trouble is that the GC freeing Parent p will free the memory allocated for Child while doStuff is executing. GC has been observed to do this in practice. A potential fix if GC.KeepAlive
was available:
// BAD CODE with potential for SIGSEGV
for (Parent p : getParents()) {
p.getChild().doStuff();
GC.KeepAlive(p);
}
I could e.g. call toString
on p, but I won't be doing anything with its output. I could poke p into an array temporarily, but how do I know the JVM won't discard the store? Etc.