当前位置: 首页 > 面试题库 >

考虑Policy.getPolicy()的原因是什么,因为它将保留对上下文的静态引用并可能导致内存泄漏

冯霖
2023-03-14
问题内容

我只是从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来解决它。

更新

我忽略了静态块部分。这里是。这是关键。实际上,它已经html" target="_blank">缓存了策略。那么为什么还要缓存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类获取垃圾,从而导致烫发代空间泄漏。



 类似资料:
  • 初学者最常见的错误是,您试图“静态”地使用类属性,而不创建该类的实例。它会给您留下前面提到的错误消息: 您可以将非静态方法设置为静态方法,也可以将该类的实例设置为使用其属性。 为什么?我不是要求解决办法。如果知道背后的原因是什么,我将不胜感激。最核心的原因!

  • 我有一个复杂的应用程序,有很多第三方库,动态加载的插件。并且在main退出后,某个东西会导致应用程序崩溃()。调用堆栈指向未知地址,因此我不仅无法调试,甚至不知道崩溃发生在哪里。 我试着用运行这个应用程序--它显示了泄漏(一些千字节),但我认为它们是误报,并且/或者我无法对它们做任何处理,因为它们来自第三方。 我的问题:我相信内存泄漏不可能造成一个分段故障,至少我找不到可能的场景。但因为我不确定,

  • 我是Hibernate的新手,我正在努力学习JPA和Hibernate。 我想知道Hibernate不允许保存引用未保存的瞬态实例的对象的原因是什么?我想知道为什么这是一个问题? 我问了一个人,他们中的一些人这样回答我: 如果数据库中还没有地址记录,我们怎么可能将客户映射到地址? 和 您正在为客户分配特定地址。但地址没有任何ID 但老实说,我不理解他们。 (我知道会抛出异常,解决方案是级联,但我想

  • 问题内容: 我正在尝试编写此代码以获取第一个initialCapacity质数,然后使用java按顺序打印它们。它不起作用有两个原因,首先是我得到了错误 41:不能从静态上下文中引用非静态变量listOfPrimeNumbers 当我尝试运行程序时,即使将变量更改为static并运行程序,它也只会打印出“ 1”。因此,仅在构造函数Primes中迭代一次while循环,然后停止,无论我多么努力,我都

  • 问题内容: 关于Java的InterruptedException有一些有趣的问题和答案,例如Java中的InterruptedException 的原因和处理InterruptedException。但是,它们都没有告诉我InterruptedException的可能来源。 像SIGTERM,SIGQUIT,SIGINT这样的OS信号呢?在命令行上按CTRL-C是否会产生InterruptedE