Re: JavaMemoryModel: A problematical case for finalizers

From: Jerry Schwarz (jerry.schwarz@oracle.com)
Date: Wed Apr 09 2003 - 12:25:21 EDT


Bill writes

>Note that declaring the send and finalize methods as synchronized with fix
>the problem.

I believe it does not.

A. The lock might not part of the object. It might, for example, be pointed
to by the object. The code would then only need to hold a pointer to the
lock, not to the object itself. This would be plausible if there was some
hardware synchronization operations that only worked on a specific area of
memory. (I have no idea if there is any such hardware.)

B. Consider the code

     Foo f = new Foo(...);
     f.send(...);
     f = null;

In this case the compiler can determine that f is never accessible from
another thread and therefore it doesn't have to actually perform the
lock/unlock and so it doesn't need to hold onto the pointer to f. (It still
needs to do memory barriers as appropriate, but those do not always require
use of the pointer to f).

> So would a call to System.keepAlive(this) at the end of the send method,
> if people are interested in that.

This is the only way. And this will work only if the semantics of
System.keepAlive specifically require that it do so. Merely giving the
semantics in terms of operations on a hidden volatile doesn't do the job
because it is possible (indeed we expect) that the compiler will optimize
away the actual operations on the volatile.

At 07:43 AM 4/9/2003, Bill Pugh wrote:
>In talking about finalizers with Doug Lea, I mentioned a scenario which I
>thought everyone knew about but Doug hadn't considered. He suggested I share it
>with everyone.
>
>Consider
>
>public class Foo {
> OutputStream out;
>
> public Foo(...) {
> out = ...;
> }
>
> public void send(...) {
> byte [] buf = ...;
> out.write(buf);

> }
> protected void finalize() {
> out.close();
> }
> }
>
>Now consider the code:
>
> { Foo f = new Foo(...);
> f.send(...);
> }
>
>Now within the code for send, a VM might try to optimize the call to
>out.write into a tail call to out.write.
>
>The VM could also inline the call to send.
>
>In this situation, there wouldn't be any live reference to the Foo object
>from the stack during the call to write. However, the write method could
>take a very long time to execute if it is pushing a large amount of data
>down a narrow pipe. So the Foo object could be finalized, and the output
>stream be closed, while the output stream is still being written to.
>
>Are we happy to declare such code broken?
>
>Note that declaring the send and finalize methods as synchronized with fix
>the problem. So would a call to System.keepAlive(this) at the end of the
>send method, if people are interested in that.
>
> Bill
>-------------------------------
>JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel

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



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