RFR: JDK-8080225: FileInputStream cleanup should be improved
Peter Levart
peter.levart at gmail.com
Tue Jun 30 18:22:58 UTC 2015
Hi,
As part of JEP 132 (More-prompt finalization) I wanted to find out what
it would take to convert finalization-based cleanup code used in a JDK
class to PhantomReference-based.
In FileInputStream case, the state needed for clean-up is stored in a
FileDescriptor referenced from FileInputStream. To make things
complicated, FileDescriptor instance can be shared among
FileInputStream(s), FileOutputStream(s) and/or RandomAccessFile(s).
Shared FileDescriptor instance keeps track (using strong references) of
any FileInputStream, FileOutputStream or RandomAccessFile it is
registered with (FileDescriptor.attach(Closeable)). A graph of
FileInputStream(s), FileOutputStream(s) and/or RandomAccessFile(s)
sharing a FileDescriptor is therefore strongly connected in all
directions. FileInputStream and FileOutputStream override finalize()
method, RandomAccessFile doesn't. When all FileInputStream(s),
FileOutputStream(s) and/or RandomAccessFile(s) connected together with
the shared FileDescriptor become eligible for finalization, finalize()
methods of FileInputStream(s) and FileOutputStream(s) get called. They
delegate to stream close() method(s) in turn which delegate to
FileDescriptor.closeAll() which close()s all streams sharing the
FileDescriptor and finally calls-back into the 1st stream which invoked
closeAll() to close the FileDescriptor (via the call to native
[FileInputStream|FileOutputStream|RandomAccessFile].close0() method).
To untangle this knot, I had to refactor some internal logic:
http://cr.openjdk.java.net/~plevart/jdk9-dev/8080225_FileStreamCleanUp/webrev.01/
Since all native
[FileInputStream|FileOutputStream|RandomAccessFile].close0() methods do
the same thing with FileDescriptor, I moved the method to FileDescriptor
and made it static while adding an int fd (UNIX) / long handle (Windows)
parameter. Clean-up action invokes this method when all connected
stream(s) and FileHandle objects are already gone. The clean-up thunk is
registered in initFd (UNIX) / initHandle (Windows) method invoked from
JNI code of FileInputStream, FileOutputStream or RandomAccessFile (see
modified SET_FD macro in io_util_md.h). Clean-up registration therefore
only happens for FileInputStream, FileOutputStream and RandomAccessFile
(the later therefore gets automatic cleanup which was not present
before). All other usages of FileDescriptor throughout JDK don't
register cleanup and therefore behave unchanged.
all java/io jtreg tests pass except of course the following two:
JT Harness : Tests that failed
java/io/FileInputStream/FinalizeShdCallClose.java: Test to ensure that
FIS.finalize() invokes the close() method as per the specification.
java/io/FileOutputStream/FinalizeShdCallClose.java: Test to ensure that
FOS.finalize() invokes the close() method as per the specification.
They don't even compile, since the removal of overriding
File[Input|Output]Stream.finalize() method which throws IOException
exposes Object.finalize() which throws Throwable. The tests override
File[Input|Output]Stream classes and finalize() methods, calling
super.close(). This change is therefore not entirely source-compatible,
but removing finalization from the File streams can not be performed
without the removal of the finalize() methods, so if this is the
direction to be taken, such source-incompatibility has to be taken into
account. I don't belive there are many File stream subclasses that
override finalize() and call super.finalize(). Wait a second, there are
two in JDK itself (Socket[Input|Output]Stream), but they override
finalize() to "disable" finalization - making it a no-op. Removing both
overrides therefore removes no-op finalization from Socket streams too...
The presented patch uses sun.misc.Cleaner for demonstration purposes
only. I don't know if it's use in this scenario is correct since closing
the file can be a blocking operation and Cleaner(s) are executed by
ReferenceHandler thread. I think a PhantomCleaner presented in my
proposal for JEP-132 which is executed by same thread(s) as finalizers
is more suitable for this purpose.
So, what do you think? Is this the direction to evolve File stream
automatic clean-up to?
Regards, Peter
More information about the core-libs-dev
mailing list