Java 避免PermGen内存不足和超出GC开销限制

Java 避免PermGen内存不足和超出GC开销限制,java,garbage-collection,classloader,java-6,permgen,Java,Garbage Collection,Classloader,Java 6,Permgen,我正在尝试生成类并在运行时加载它们。 我正在使用ClassLoader对象来加载类。由于我不想耗尽PermGen内存,因此我会不时取消引用类装入器并创建一个新的类装入器来装入要使用的新类。这似乎工作正常,而且我的内存中没有PermGen。 问题是,当我这样做时,过了一段时间后,我得到以下错误: java.lang.OutOfMemoryError: GC overhead limit exceeded 所以我的问题是,我应该什么时候取消引用类加载器以避免这两个错误?:我应该在代码中监视Per

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

java.lang.OutOfMemoryError: GC overhead limit exceeded 
所以我的问题是,我应该什么时候取消引用类加载器以避免这两个错误?:
我应该在代码中监视
PermGen
的使用情况,以便在
PermGen
使用接近极限时取消引用类加载器并调用
System.gc()

或者我应该采用另一种方法吗?
谢谢

对此没有唯一正确的答案

一方面,如果断开类加载器的链接可以解决permgen泄漏问题,那么您应该继续这样做

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

  • 堆太小,无法满足应用程序的要求

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

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



不要调用
System.gc()
。这不会有帮助。

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

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

我在卸载类时也遇到过类似的情况

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

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

有时,如果您需要完整的GC,JVM会延迟类卸载事件,这会导致以后出现各种问题

下面是我发现的一种强制JVM收集永久空间的有效技术

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;
        }
    }
}   
publicstaticvoidforcepermspacegc(双因素){
if(PERM_SPACE_MBEAN==null){
//可能不是热点JVM
返回;
}
否则{
双f=((双)getPermSpaceUsage())/getPermSpaceLimit();
如果(f>因子){
List bloat=new ArrayList();
int spree=0;
int n=0;
while(狂欢<5){
试一试{

字节[]b=新字节[1我正在使用jvisualvm监视堆的使用情况,最大大小为1 Gb,使用情况在200 mb到600 mb之间变化,因此这远远超出了限制。@otonakav-可能您的GC调优参数有问题。可能有一个限制可以最大限度地减少我取消引用类装入器的次数,这样GC就不会运行太多tim是的,但是我假设如果有大量的heap和PermGen,GC就不会运行,这仅仅是因为我取消了对类加载器的引用,特别是当它将超过开销限制时。我试图指出,问题可能出在类加载器的使用上,而不是类加载器本身。