5

我正在尝试生成类并在运行时加载它们。
我正在使用一个ClassLoader对象来加载类。因为我不想耗尽PermGen内存,所以我不时取消引用类加载器并创建一个新的类加载器来加载要使用的新类。这似乎工作正常,我没有PermGen内存不足。问题是当我这样做时,一段时间后我收到以下错误:

java.lang.OutOfMemoryError: GC overhead limit exceeded 

所以我的问题是,我什么时候应该取消引用类加载器以避免这两个错误?:
我应该在我的代码中监视PermGen使用情况,以便我取消引用类加载器并System.gc()PermGen使用量接近限制时调用吗?
还是我应该采用不同的方法?
谢谢

4

3 回答 3

6

对此没有单一的正确答案。

一方面,如果取消链接类加载器正在解决您的 permgen 泄漏问题,那么您应该继续这样做。

另一方面,“超出 GC 开销限制”错误意味着您的应用程序花费了太多时间进行垃圾收集。在大多数情况下,这意味着您的堆太满了。但这可能意味着以下两件事之一:

  • 堆对于您的应用程序的要求来说太小了。

  • 您的应用程序存在内存泄漏。

您可以假设问题出在前一个问题上,只需增加堆大小即可。但是如果真正的问题是后一个问题,那么增加堆大小只是推迟不可避免的事情......正确的做法是找到修复内存泄漏。


不要打电话System.gc()。它不会有帮助。

于 2013-10-24T17:49:44.597 回答
1

您是否多次加载同一个类?因为你应该缓存加载的类。

如果没有,您要加载多少个类?如果它们足够多,您可能必须修复加载类的限制(这个数字可以基于堆大小或基于加载类需要多少内存的数字)并在加载下一个时丢弃最少使用的类一。

于 2013-10-24T17:54:04.380 回答
1

我在卸载类时遇到了类似的情况。

我正在使用几个类加载器来模拟 JUnit 测试中的多个 JVM(这通常用于与 Oracle Coherence 集群一起使用,但我也成功地使用这种技术在 JVM 中启动了多节点 HBase/Hadoop 集群)。

由于各种原因,测试可能需要重新启动这种“虚拟”JVM,这意味着放弃旧的 ClassLoader 并创建新的 ClassLoader。

如果您进行 Full GC,有时 JVM 会延迟类卸载事件,这会导致以后出现各种问题。

我发现一种对强制 JVM 收集 PermSpace 很有用的技术如下。

public static void forcePermSpaceGC(double factor) {
    if (PERM_SPACE_MBEAN == null) {
        // probably not a HotSpot JVM
        return;
    }
    else {
        double f = ((double)getPermSpaceUsage()) / getPermSpaceLimit();
        if (f > factor) {

            List<String> bloat = new ArrayList<String>();
            int spree = 0;
            int n = 0;
            while(spree < 5) {
                try {
                    byte[] b = new byte[1 << 20];
                    Arrays.fill(b, (byte)('A' + ++n));
                    bloat.add(new String(b).intern());
                    spree = 0;
                }
                catch(OutOfMemoryError e) {
                    ++spree;
                    System.gc();
                }
            }
            return;
        }
    }
}   

完整的源代码

我正在使用 String 填充 PermSpace,intern()直到 JVM 收集它们。

  • 我正在使用该技术进行测试
  • 硬件/JVM版本的各种组合可能需要不同的阈值,因此重启整个JVM通常比强制它正确收集所有垃圾更快
于 2013-10-24T23:28:04.140 回答