考虑 Policy.getPolicy() 的原因是什么,因为它会保留对上下文的静态引用并可能导致内存泄漏 [英] What is the reason that Policy.getPolicy() is considered as it will retain a static reference to the context and can cause memory leak

查看:18
本文介绍了考虑 Policy.getPolicy() 的原因是什么,因为它会保留对上下文的静态引用并可能导致内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚阅读了一些来自 org.apache.cxf.common.logging.JDKBugHacks 的源代码,也在http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java.为了使我的问题清楚,不要太宽泛.:)我只问其中的一段代码.

I just read some source code is from org.apache.cxf.common.logging.JDKBugHacks and also in http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/JreMemoryLeakPreventionListener.java. In order to make my question clear not too broad. :) I just ask one piece of code in them.

           // 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 来解决它.

But I didn't understand this comment. "Calling getPolicy retains a static reference to the context class loader". And they trying to use JDKBugHacks to work around it.

更新

我忽略了静态块部分.这里是.这是关键.实际上它已经缓存了策略.那么为什么还要缓存 contextClassLoader 呢?在评论中,它声称 @deprecated 从 JDK 1.4 版开始 - 被 java.security.Policy 取代.

I overlooked the static block part. Here it is. This is the key. Actually it already has policy cached. So why cache contextClassLoader also? In comment, it claims @deprecated as of JDK version 1.4 -- Replaced by 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 源代码.

I also add the getPolicy source code.

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;
}

其实我挖掘得更深一些,我发现了一些有趣的事情.最近有人向 apache CXF 报告了一个关于 org.apache.cxf.common.logging.JDKBugHacks 这段代码的错误.

Actually I dig deeper, I find some interesting thing. Someone report a bug to apache CXF about the org.apache.cxf.common.logging.JDKBugHacks for this piece code recently.

为了禁用 url 缓存,JDKBugHacks 运行:

In order for disabling url caching, JDKBugHacks runs:

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

设置 java.protocol.handler.pkgs 系统属性时,在特定情况下可能会导致系统类加载器和文件协议处理程序之间出现死锁(例如,如果文件协议 URLStreamHandler 是信号灯).除此之外,上面的代码实际上只是为了将defaultUseCaches设置为false,因此可以避免实际打开连接,以加快执行速度.

When having the java.protocol.handler.pkgs system property set, that can lead to deadlocks between the system classloader and the file protocol Handler in particular situations (for instance if the file protocol URLStreamHandler is a signleton). Besides that, the code above is really there for the sake of setting defaultUseCaches to false only, so actually opening a connection can be avoided, to speed up the execution.

所以修复是

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 存在相同的问题,但并未弃用.

It's normal that JDK or apache cxf to have some minor bugs. And normally they will fix it. javax.security.auth.login.Configuration has the same issues with Policy but it's not Deprecated.

推荐答案

java 6 中的 Policy 类包含对类加载器的静态引用,该类加载器在第一次访问该类时初始化为当前线程上下文类加载器:

The Policy class in java 6 contains a static reference to a classloader that is initialized to the current threads context classloader on the first access to the class:

private static ClassLoader contextClassLoader;

static {
contextClassLoader =
    (ClassLoader)java.security.AccessController.doPrivileged
            (new java.security.PrivilegedAction() {
            public Object run() {
                return Thread.currentThread().getContextClassLoader();
            }
    });
};

Tomcat 的生命周期侦听器确保从上下文类加载器设置为系统类加载器的已知环境中初始化此类.如果这个类是第一次从 webapp 内部访问的,它会保留对 webapps 类加载器的引用.这将防止 webapps 类被垃圾收集,造成永久空间的泄漏.

Tomcats lifecycle listener is making sure to to initialize this class from within a known environment where the context classloader is set to the system classloader. If this class was first accessed from within a webapp, it would retain a reference to the webapps classloader. This would prevent the webapps classes from getting garbage collected, creating a leak of perm gen space.

这篇关于考虑 Policy.getPolicy() 的原因是什么,因为它会保留对上下文的静态引用并可能导致内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆