Re: JavaMemoryModel: Finalization idioms

From: Jeremy Manson (jmanson@cs.umd.edu)
Date: Mon May 02 2005 - 12:57:24 EDT


David Holmes wrote:
> Jeremy Manson wrote:
>
>>To David D. and Evan - You could finalize man in any of the places David
>>H. mentions if useA() and useB() don't access this, and are inlined by
>>the compiler. In such code, there would be no uses of man after its
>>initialization.
>
>
> Thanks Jeremy, I thought for a moment I had completely misunderstood this
> issue once again. Though your clarification does restrict the problem to a
> subset of situations to what I was thinking - ie I don't completely
> understand it either.

I should clarify: the above was intended as an easy-to-understand
example, not a full list of cases in which you could finalize man early.
  There are plenty of others; basically, anything in which there is no
synchronization and no write of a reference to man into the heap can be
finagled into a situation where man is finalized early.

> However, Jeremy also indicated that the premature finalization could only
> occur if the methods useA and useB don't refer to 'this' - yet the JIT
> doesn't know this without examining the internals of those methods, which
> again seems unreasonable to me.

It is possible to finalize early if useA and useB refer to 'this'. What
would happen in practice is that the use of 'this' would get optimized away.

> I find it hard to believe that the VM/JIT would actively try to perform this
> optimization. My thought - which could be quite wrong - was that it arose as
> a side-effect of the JIT's actions eg. a local reference is stored in a
> register and so is not seen by GC and thus an object is considered
> unreachable. Based on that case you need the sync block in the current
> method to force the JIT to consider that before storing the local in a
> register (how much time would such an analysis take? would it be worth it?).

As a side note: it is not true that if a pointer is allocated in a
register, the object is unreachable. Obviously, pointers stored in
registers imply reachability. What will generally happen is that all
references to the object will be optimized out of the program, and so
the reference isn't stored anywhere anymore.

Let's take a more detailed look at your example, so that everyone knows
what we are talking about, exactly. We'll use a case where useA and
useB both make reference to this:

    void someMethod() {
      ResourceManager man = new ResourceManager();
          // man could be finalized here
      int result1 = man.useA();
          // or here
      int result2 = man.useB();
          // or here
    }

And then useA and useB are defined:

class ResourceManager {

  final int a = 1;
  final int b = 2;

  int useA() {
     System.err.println(this.a);
  }

  int useB() {
     System.err.println(this.b);
  }
  // and a finalizer
}

useA and useB can get inlined:

    void someMethod() {
      ResourceManager man = new ResourceManager();
          // man could be finalized here
      System.err.println(man.a);
          // or here
      System.err.println(man.b);
          // or here
    }

And then the compiler can do constant folding:

    void someMethod() {
      ResourceManager man = new ResourceManager();
          // man could be finalized here
      System.err.println("1");
          // or here
      System.err.println("2");
          // or here
    }

Et voila, man is never used, and finalization can occur directly after
construction.

> (I resent the use of "naive" there. I don't consider it to be naive to
> think that an object is reachable when it is still being used!)

It was there in the previous version of the JLS. So we left it that way :)

                                        Jeremy
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:01:10 EDT