RFR JDK-8185582, Update Zip implementation to use Cleaner, not finalizers
Peter Levart
peter.levart at gmail.com
Tue Oct 31 17:30:25 UTC 2017
Hi Sherman,
On 10/31/17 00:32, Xueming Shen wrote:
> On 10/30/2017 01:34 PM, Peter Levart wrote:
>>
>> The Inflater and Deflater now look fine (except you don't have to
>> check for cleanable != null any more in Inflater.end()).
>>
>> But what shall we do with ZipFile?
>>
>
> Peter,
>
> The fundamental issue here is the gap between the resource allocation
> and the cleaner registration, as far as these two are not an atomic
> operation, it's hard to handle it in the normal use scenario. You might be
> able to workaround it by registering the cleaner first and then send the
> resource reference into the cleaner, as we are going to do for the
> deflater/
> inflater.
RIght. Finalization, as designed, usually guides the programmer to not
mess this order. The finalizable instance is registered as part of
Object.<init> constructor call. When resource allocation happens in the
subclass constructor(s), all is well, because code of subclass
constructors is executed after Object.<init> successfully returns.
Subclassing PhantomCleanable<T> has this same good property when
resource allocation is performed in the PhantomCleanable's subclass
constructor(s).
> But it appears to be a more general issue and in some circumstance
> even the "register-first-allocate-assign-in-later" approach might fail.
> For example, you have N resource to allocate, something goes wrong
> between the first and the Nth resource allocation completed/or simply say
> before you can reach the "register()".
If you really do "register-first-allocate-assign-in-later" then there is
no problem as those resources that are assigned are the resources that
were allocated. The cleanup function should selectively deallocate the
resources that were assigned (using null or some special default value
to identify resources that weren't).
> The question then I would like to ask
> again is if this is really something we want to support/cover with the
> Cleaner
> mechanism. It doesn't appear to be supported under the finalize()
> mechanism.
> For example, if someone throws out an exception inside the constructor, in
> normal use scenario, regardless you catch or not catch that exception
> (outside the constructor), the finalize() method is probably not going to
> be called by the finalizer for this partially/incompletely constructed
> object,
> if you don't purposely do something special to publish the object.
Wrong. Try this example:
public class TestFinalization {
final int resource;
public TestFinalization() {
if (true) {
// by the time this is thrown, the object is already registered
// for finalization....
throw new RuntimeException();
}
resource = 42;
}
@SuppressWarnings("deprecation")
@Override
protected void finalize() {
System.out.println("finalize() called: resource=" + resource);
}
public static void main(String[] args) throws Exception {
try {
new TestFinalization();
} catch (RuntimeException e) {
System.out.println("Exception caught");
}
System.gc();
Thread.sleep(1000L);
}
}
It prints the following:
Exception caught
finalize() called: resource=0
> Sure
> arguably It appears to be out of the scope of Cleaner API and the only
> thing
> needs to be addressed here is whether or not register(..) operation
> fails and
> throws an Error. But it might be helpful to see if there is any
> different opinion
> before going further?
I don't see much difference between finalization and Cleaner mechanism.
The main difference is that with finalization, the object that is being
tracked is also the object that contains the state and logic needed for
cleanup. Cleaner API decouples those two aspects. The low-level
(extending PhantomCleanable<T>) API also encourages the correct order of
things: 1st register then allocate. If we either expose the low-level
API to the public or make some additions to the high-level API to
encourage the same, all will be well.
Regards, Peter
>
> Sherman
>
>
>
>
>
More information about the core-libs-dev
mailing list