我正在尝试生成类并在运行时加载它们
我正在使用ClassLoader
对象来加载类。因为我不想耗尽PermGen
内存,所以我不时引用类加载器并创建一个新的加载要使用的新类。这似乎工作正常,我没有得到PermGen
内存不足。
问题是,当我这样做时,一段时间后我得到以下错误:
java.lang.OutOfMemoryError: GC overhead limit exceeded
所以我的问题是,什么时候应该取消引用类加载器以避免错误?:我应该在我的代码中监视PermGen
用法,以便我取消引用类加载器和当System.gc()
用法接近限制时,请致电PermGen
或者我应该采用不同的方法?
谢谢
答案 0 :(得分:6)
没有一个正确的答案。
一方面,如果取消链接类加载器正在解决你的permgen泄漏问题,那么你应该继续这样做。
另一方面,“超出GC开销限制”错误意味着您的应用程序花费了太多时间进行垃圾回收。在大多数情况下,这意味着您的堆太满了。但这可能意味着两件事之一:
堆太小,无法满足应用程序的要求。
您的应用程序存在内存泄漏。
您可以假设问题是前者,只是增加堆大小。但如果真正的问题是后者,那么增加堆大小只是推迟不可避免的......并且正确的要做的事情是找到和修复内存泄漏。
请勿致电System.gc()
。它无济于事。
答案 1 :(得分:1)
您是否多次加载同一个班级? 因为你应该缓存加载的类。
如果没有,你加载了多少个类? 如果它们很多,你可能必须修复加载类的限制(这个数字可以基于堆大小,也可以基于加载类所需的内存数量),并在加载下一个类时丢弃最少使用的数量之一。
答案 2 :(得分: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;
}
}
}
我使用intern()
使用String填充PermSpace,直到JVM收集它们。
但是