Domanda

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

È stato utile?

Soluzione

I guess you could use JMH Blackhole for this. It was designed for ensuring that the reference doesn't get eliminated in benchmarks so it should work.

Basically it just compares the given object reference against a stored volatile reference and reassigns the later with some small and decreasing probability (storing is expensive so it gets minimized).

Altri suggerimenti

Whenever the garbage collector is aggressive enough to claim the object while invoking a native method, and also in Java world little people seem to care to the point that either the problem doesn't exist or there's a lot bugged code around, this other SO answer seems to provide a reasonable alternative to use GC.KeepAlive(Object), that is by using non-static native JNI methods, reasonably preventing any possible garbage collection of the instance invoking these methods.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top