JavaMemoryModel: A problematical case for finalizers

From: Bill Pugh (pugh@cs.umd.edu)
Date: Wed Apr 09 2003 - 10:43:32 EDT


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



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