JDK-6568138 : FileDescriptors can sometimes escape being closed by the finalizer
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2007-06-11
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
7 b15Fixed
Related Reports
Relates :  

> We have a test program that has 10 threads that exec 1000 processes
> one at a time, wait for it to terminate then repeat. On linux this
> quickly encounters IOException because the maximum number of open
> files is exceeded. The test program is a bad citizen and doesn't
> explicitly close the process streams.
> On JDK 1.4.2, 1.5 and 1.6 the test still passes because eventually the
> finalization of the streams closes the underlying fds.
> In Java 7 the fds are never reclaimed and the test program goes into
> an infinite process of throwing IOExceptions.
> Looking at 6524062 and the code in FileInputStream and FileDescriptor
> I think I see why. The UNIXProcess class creates FileDescriptor
> objects and passes them to FIS/FOS constructors. The FileDescriptor
> constructor sets the useCount to 1. The FIS/FOS constructor increments
> the useCount to 2. When close() is called during finalization we have
> the following:
>     int useCount = fd.decrementAndGetUseCount();
>     if ((useCount <= 0) || !isRunningFinalize()) {
>         close0();
>         }
> We only decremented the useCount *once* so it is still 1, hence we
> will not call close0() if finalization is active. Hence the fd gets
> leaked.
> It seems to me that the FileDescriptor constructor should not be
> initializing the useCount to 1 as the FD is not yet in use.

EVALUATION Notes by ###@###.### The background to the changes in jdk7 is that several streams could be using the same java.io.FileDescriptor. If one of them becomes unreachable and is finalized then the finalizer would close the underlying file descriptor from under the streams still using the file. As this is 10+ year old code we knew that any changes would be risky and this is why the changes went in early into jdk7. There have been a few regressions and this looks like another one. In this case, you seem to be right and the no-arg constructor should initialize the count to 0 rather than 1.