Suspected regression: fix for 6735255 causes delay in GC of ZipFile InputStreams, increase in heap demand
David Holmes
David.Holmes at oracle.com
Sun Apr 3 23:04:48 UTC 2011
Hi Neil,
Neil Richards said the following on 04/02/11 11:28:
> David, I can't claim to have reached true enlightenment wrt the section
> of the JLS that you point to - I suspect I'll need to lie down in a
> darkened room with a dampened flannel across the brow and ponder the
> nature of things a while to get there :-)
>
> In the meantime, can you (or other knowledgeable GC folk) advise whether
> it has any implications which would cause the current suggested fix to
> be unsuitable?
> (To recap, the current suggestion has the ZipFileInflaterInputStream's
> close() method synchronized on itself, and called from its finalize()
> method. The close() method has both the read and write of the 'isClosed'
> field).
>
> Any reassurance (or otherwise) gratefully accepted on this matter,
I don't fully understand the object relationships here so I'll just make
a couple of observations on the synchronization in this code:
public synchronized void close() throws IOException {
if (!isClosed) {
super.close();
if (false == inFinalizer)
releaseInflater(inf);
isClosed = true;
}
}
public int available() throws IOException {
if (isClosed)
return 0;
long avail = zfin.size() - inf.getBytesWritten();
...
}
protected void finalize() throws IOException {
inFinalizer = true;
close();
}
1. If a call to close() occurs around the same time as finalization
occurs then the finalizer thread will set inFinalizer to true, at which
point the thread executing close() can see it is true and so may skip
the releaseInflater(inf) call.
2. As isClosed is not volatile, and available() is not synchronized, a
thread calling available() on a closed stream may not see that it has
been closed and so will likely encounter an IOException rather than
getting a zero return.
Even if #1 is not a practical problem I'd be inclined to make the
finalizer synchronized as well. By doing that you're effectively
ensuring that premature finalization of the stream won't happen.
For #2 it is a tricky call. If you don't actually expect the stream
object to be used by multiple threads then using a synchronized block to
read isClosed will be cheap in VMs that go to great effort to reduce the
cost of unnecessary synchronization (eg biased-locking in hotspot).
Otherwise making isClosed volatile is likely the better option.
HTH
David
More information about the core-libs-dev
mailing list