在org.apache.catalina.core.JreMemoryLeakPreventionListener中急切调用URLConnection的setDefaultUseCaches(false)的原因是什么

时间:2011-08-15 22:57:42

标签: api memory-leaks java

这个问题可能有点难以找到答案。这是What is the reason that Policy.getPolicy() is considered as it will retain a static reference to the context and can cause memory leak系列中的一个问题。您可以阅读它,以便了解更多背景信息。

org.apache.cxf.common.logging.JDKBugHacksorg.apache.catalina.core.JreMemoryLeakPreventionListener获取源代码。

有一段代码。在这里。

URL url = new URL("jar:file://dummy.jar!/"); 
URLConnection uConn = new URLConnection(url) {

    @Override
    public void connect() throws IOException{ 
        // NOOP
    }

};
uConn.setDefaultUseCaches(false);

评论说

/*
 * Several components end up opening JarURLConnections without
 * first disabling caching. This effectively locks the file.
 * Whilst more noticeable and harder to ignore on Windows, it
 * affects all operating systems.
 * 
 * Those libraries/components known to trigger this issue
 * include:
 * - log4j versions 1.2.15 and earlier
 * - javax.xml.bind.JAXBContext.newInstance()
 */

但我很难理解。为什么他们急切地打电话给setDefaultUseCaches(false)以及为什么在Windows上,默认缓存是真的有害?我在java.net.JarURLConnection找不到任何线索。

1 个答案:

答案 0 :(得分:4)

我自己找到答案。如果你认为我错了,任何人都可以纠正我。 在sun.net.www.protocol.jar.JarURLConnection。我假设这是java.net.JarURLConnection的默认实现。下面有一段代码。

如果cache设置为true,则它不会关闭JarFile的连接。这意味着它被锁定了。

class JarURLInputStream extends java.io.FilterInputStream {
        JarURLInputStream (InputStream src) {
            super (src);
        }
        public void close () throws IOException {
            try {
                super.close();
            } finally {
                if (!getUseCaches()) {
                    jarFile.close(); //will not close
                }
            }
        }
    }



    public void connect() throws IOException {
        if (!connected) {
            /* the factory call will do the security checks */
            jarFile = factory.get(getJarFileURL(), getUseCaches());

            /* we also ask the factory the permission that was required
             * to get the jarFile, and set it as our permission.
             */
            if (getUseCaches()) {
                jarFileURLConnection = factory.getConnection(jarFile);
            }

            if ((entryName != null)) {
                jarEntry = (JarEntry)jarFile.getEntry(entryName);
                if (jarEntry == null) {
                    try {
                        if (!getUseCaches()) {
                            jarFile.close();  //will not close
                        }
                    } catch (Exception e) {
                    }
                    throw new FileNotFoundException("JAR entry " + entryName +
                                                    " not found in " +
                                                    jarFile.getName());
                }
            }
            connected = true;
        }
    }