Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4167874
Votes 15
Synopsis URL-downloaded jar files can consume all available file descriptors
Category java:classes_net
Reported Against 1.2 , 1.3 , 1.2fcs , 1.4.2_04
Release Fixed 7(b48)
State 10-Fix Delivered, bug
Priority: 4-Low
Related Bugs 6349735 , 4166799 , 4175918 , 4991099 , 6501408 , 6501466
Submit Date 20-AUG-1998
Description
The JarFile objects created by sun.net.www.protocol.jar.JarFileFactory never get garbage collected, even if the classloader that loaded them goes away.  Since each one has an open file descriptor, if an RMI application or server loads classes from enough different jar codebases over time, the process runs out of file descriptors on Solaris, even if the classes have long since been garbage collected.





java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0)
Java HotSpot(TM) Client VM (build 1.3.0, mixed mode)

When JarURLConnections to entries inside a JarFile are opened, the jarfile is
cached, even when caching is explicitly turned off.

Under Win32 systems, this has the side-effect that the file can no longer be
modified (e.g. deleted). Under Linux this only results in filedescriptors being
kept open as can be seen with 'lsof'.

The source below reproduces this problem, assuming that there is a jarfile
called 'localfile.jar'.

--- BEGIN SOURCE ---import java.io.File;
import java.io.InputStream;
 
import java.net.URL;
import java.net.URLConnection;
 
/**
 * This class shows the caching bug in JarURLConnection
 *
 * @author   xxxxx@xxxxx  
 */
public class JarURLConnectionTestCase
{
    /**
     * This method opens a local file, opens a non-caching
     * URLConnection, opens a Stream on that connection, closes the
     * stream and tries to delete the file.
     *
     * On Win32 systems, this will cause an exception because the file
     * is still referenced by the URLConnection-cache
     */
    public static void main(String[] args)
        throws Exception
    {
        URL entryURL
            = new URL("jar:file:localfile.jar!/META-INF/MANIFEST.MF");
        URLConnection connection = entryURL.openConnection();
 
        // BUG: turn off caching; this does NOT work
        connection.setUseCaches(false);
 
        // open and close a stream
        InputStream stream = connection.getInputStream();// causes the caching
        stream.close();
 
        // now delete the file. This fails, because the connection
        // keeps a cache-reference
        File file = new File("localfile.jar");
        System.err.println("Attempting to delete localfile.jar");
        if (!file.delete()) {
            System.err.println("Deletion failed, bug exists!");
        }
    }
}
--- END SOURCE ---

According to our profiler, the caching happens in
sun.net.www.protocol.jar.JarFileFactory:80
(Review ID: 124469)
======================================================================
Work Around
use getJarFile() then call JarFile.close() after you are done with the
particular JarFile.

---------------------

This is probably a bad idea. I suspect this will cause major breakage.
See the evaluation.

  xxxxx@xxxxx   1998-10-26
Evaluation
This has been fixed some time ago. Call setUseCaches(false) to turn
off caching.


  xxxxx@xxxxx   2001-11-13

We probably should think about adding an API to URLConnection
to switch off/on particular caching. setDefaultUseCaches(false)
switches off caching for all types of connections.
This will be fixed very soon in jdk7 (next few weeks).
Posted Date : 2009-01-27 11:56:21.0
Comments
  
  Include a link with my name & email   

Submitted On 26-OCT-2001
Hedin
There is a workaround:
---
static void clearJarURLCache() throws Exception
{
 Class jarFileFactory = Class.forName
("sun.net.www.protocol.jar.JarFileFactory");

 Field fileCache = jarFileFactory.getDeclaredField
("fileCache");
 Field urlCache = jarFileFactory.getDeclaredField
("urlCache");

 fileCache.setAccessible(true);
 fileCache.set(null,new HashMap());

 urlCache.setAccessible(true);
 urlCache.set(null,new HashMap());
}
---
This is clearly a hack, but I didn't find better solution 
yet.


Submitted On 03-DEC-2002
bert69
The other problem caused by this is if the JAR file changes,
trying to load a resource from the new JAR results in
variuos exceptions. This is because the JAR loader uses the
previously cached JAR index, which may either fail to
contain the requested resource, or point to the wrong
location within the new file.

Even if caching is enabled, the file should be checked for
chamges in order to invalidate entries as needed.


Submitted On 28-OCT-2008
bestsss
there is FAR easier workaround:
closing the JarFile returned by getJarFile() of JarURLConnection. The latter may be obtained by dummy URL("jar:://file_path/!").openConnection()

The downside of the workaround is the necessity to keep track of the opened jar files (or jar URLs). It can be implemented by altering the default url jar handler, yet it's a cumbersome task and requires -D param on start up.
______
The above workaround actually  exposes side (security) effects b/c caching allows an arbitrary 'close' of any open stream provided via the (cached) JarFile.



PLEASE NOTE: JDK6 is formerly known as Project Mustang