我只是从org.apache.cxf.common.logging.JDKBugHacks和http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener中读取了一些源代码 。 Java的。为了使我的问题讲得不太广泛。:)我只问其中的一段代码。
// Calling getPolicy retains a static reference to the context // class loader. try { // Policy.getPolicy(); Class<?> policyClass = Class .forName("javax.security.auth.Policy"); Method method = policyClass.getMethod("getPolicy"); method.invoke(null); } catch (Throwable e) { // ignore }
但是我不明白这个评论。“调用getPolicy会保留对上下文类加载器的静态引用”。他们试图使用JDKBugHacks来解决它。
更新
我忽略了静态块部分。这里是。这是关键。实际上,它已经缓存了策略。那么为什么还要缓存contextClassLoader?在注释中,它声明自JDK 1.4版起@deprecated-由java.security.Policy取代。
我已经仔细检查了java / security / Policy.java的代码。它确实删除了缓存的类加载器。所以我的怀疑是正确的!:)
@Deprecated public abstract class Policy { private static Policy policy; private static ClassLoader contextClassLoader; static { contextClassLoader = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction<ClassLoader>() { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } }); };
我还添加了getPolicy源代码。
public static Policy getPolicy() { java.lang.SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(new AuthPermission("getPolicy")); return getPolicyNoCheck(); } static Policy getPolicyNoCheck() { if (policy == null) { synchronized(Policy.class) { if (policy == null) { String policy_class = null; policy_class = java.security.AccessController.doPrivileged (new java.security.PrivilegedAction<String>() { public String run() { return java.security.Security.getProperty ("auth.policy.provider"); } }); if (policy_class == null) { policy_class = "com.sun.security.auth.PolicyFile"; } try { final String finalClass = policy_class; policy = java.security.AccessController.doPrivileged (new java.security.PrivilegedExceptionAction<Policy>() { public Policy run() throws ClassNotFoundException, InstantiationException, IllegalAccessException { return (Policy) Class.forName (finalClass, true, contextClassLoader).newInstance(); } }); } catch (Exception e) { throw new SecurityException (sun.security.util.ResourcesMgr.getString ("unable to instantiate Subject-based policy")); } } } } return policy; }
其实我更深入,发现一些有趣的事情。最近有人向CXF报告了有关此段代码的org.apache.cxf.common.logging.JDKBugHacks的错误。
为了禁用URL缓存,JDKBugHacks运行:
URL url = new URL("jar:file://dummy.jar!/"); URLConnection uConn = url.openConnection(); uConn.setDefaultUseCaches(false);
设置java.protocol.handler.pkgs系统属性时,在某些情况下(例如,如果文件协议URLStreamHandler是一个Signleton),这可能导致系统类加载器和文件协议处理程序之间出现死锁。除此之外,上面的代码实际上只是为了将defaultUseCaches设置为false,因此实际上可以避免打开连接以加快执行速度。
所以解决方法是
URL url = new URL("jar:file://dummy.jar!/"); URLConnection uConn = new URLConnection(url) { @Override public void connect() throws IOException { // NOOP } }; uConn.setDefaultUseCaches(false);
JDK或apache cxf出现一些小错误是正常的。通常他们会修复它。javax.security.auth.login.Configuration与Policy存在相同的问题,但尚未弃用。
Java 6中的Policy类包含对类加载器的静态引用,该类加载器在首次访问该类时会初始化为当前线程上下文类加载器:
private static ClassLoader contextClassLoader; static { contextClassLoader = (ClassLoader)java.security.AccessController.doPrivileged (new java.security.PrivilegedAction() { public Object run() { return Thread.currentThread().getContextClassLoader(); } }); };
Tomcats生命周期侦听器确保从已知环境中初始化该类,在该环境中,上下文类装入器设置为系统类装入器。如果首先从webapp内部访问此类,它将保留对webapps类加载器的引用。这将防止webapps类获取垃圾,从而导致烫发代空间泄漏。