0

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.

user967710
  • 1,815
  • 3
  • 32
  • 58
  • 1
    Put a local variable into a stack/queue after you define it, pull it at the very ending of the method. You may rely on the result of the method (storing it somewhere), if it is present, it's obvious that all its local variables are not "active". Though, I don't understand the purpose of this. – Andrew Tobilko Aug 26 '18 at 14:06
  • The methods' endings are not trivial - it could be a bunch of returns in if/else branches or if an exception is thrown and caught by this method, that too will terminate this method's excution – user967710 Aug 26 '18 at 14:08

1 Answers1

2

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.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thanks, but I explicitly wrote "I don't want to rely on ASM - and add a try-finally wrapper to all of these methods" – user967710 Aug 26 '18 at 14:48
  • I know you did. Unfortunately, that is your only option, AFAIK. – Stephen C Aug 26 '18 at 14:50
  • why you want reference based solution. The answer is one of the best(actually best) way to notify that method has ended. – nits.kk Aug 26 '18 at 18:58
  • 2
    Actually, the JVM *does* code transformations, which incorporate the actual use of local variables and allow earlier collection of objects, which would naively be considered referenced by local variables. As “[finalize() called on strongly reachable object in Java 8](https://stackoverflow.com/q/26642153/2711488)” demonstrates, this may even apply to `this`. However, it still requires an actual garbage collection for the object to become collected. And, as a fun fact, it perverts the OP’s actual intention: the collection of the object does not prove that the method has been completed. – Holger Sep 13 '18 at 08:16