Search code examples
javaweak-referencessoft-referencesphantom-reference

any way to tell if a method ended or local in method in no longer in use?


I need some solution that will help me tell for a some methods, in a case like this:

void myMethod(...)
{
    MyObject obj = new MyObject();
    // do stuff
}

if this method has ended or if obj is unreachable (which will indicate the method has ended).

I'm writing a small java agent, and I am hoping for some technique that either will let me know for sure this method ended or obj is unreachable... In my case the "do stuff" section doesn't use obj at all. It doesn't pass this variable somewhere else or adds it to some collection.

I know that with Weak/Soft/Phantom-References I can partially achieve this. If a GC is called, then by having:

void myMethod(...)
{
    MyObject obj = new MyObject();
    WeakReference objReference = new WeakReference(obj);

    // do stuff
}

I can always verify in a different place:

    if (objReference.get() == null) ...

However, this is only maybe true if GC occurred.

Is there any alternative way to achieve this? For example, some marking the JVM may put on this variable since it is obvious this is a local that is definitely garbage-collectible...

I don't want to rely on ASM - and add a try-finally wrapper to all of these methods. Was hoping for a more subtle, reference based solution.


Solution

  • The only reliable way to do this ... that I can think of ... is to use callbacks / listeners; e.g.

    public MyClass
    
        void myMethod(Function<MyClass, Void> onCompletion) {
            try {
                // Do stuff
            } finally {
                onCompletion.apply(this);
            }
        }
    

    You could also implement this using MethodHandles.tryFinally to create method handles for your method that implement the callback by wrapping the methods.

    Anything based on Reference types is implicitly depending on garbage collection. This will be expensive, and you will have little control over when you get the notifications.


    Is there any alternative way to achieve this? For example, some marking the JVM may put on this variable since it is obvious this is a local that is definitely garbage-collectible...

    AFAIK, no there isn't. And the JVM / JIT do not do what you hypothesized; i.e. they don't mark an "obvious" local for finalization or collection ahead of a normal GC cycle.

    Why don't they? Because it would make applications slower if that happened. The only benefit is that finalization / reference processing might happen sooner, but for a well-written application that would make no difference. A well-written program should not care when finalization / reference processing happens, since the timing is explicitly not guaranteed by the specs.

    And it turns out that escape analysis doesn't help either:

    Now I am aware that the JIT may adjust the tables that tell the GC what is still in scope (see @Holger's comment; e.g. finalize() called on strongly reachable object in Java 8). But that doesn't change the method's instruction sequence. It is only the GC that pays attention to that information ... while the GC is running.