「这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战」
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exc
案例
- 在jvm参数测试中本来想测试方法区中的常量池内存溢出的异常的。但是抛出了上面的错误。
- 首先参数设置如下
-verbose:gc
-Xms20M
-Xmx20M
-Xmn10M
-XX:MetaspaceSize=5M
-XX:MaxMetaspaceSize=10M
-XX:+PrintGCDetails
-XX:SurvivorRatio=8
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=D:\jvm
-XX:+PrintFlagsFinal
- 其中-XX:MetaspaceSize=5M、-XX:MaxMetaspaceSize=10M表示方法区内存大小的限制。
public class RuntimeConstantError {
public static void main(String[] args) {
//List保持对常量池的引用。避免Full GC回收常量池
List<String> list = new ArrayList<>();
int i =0 ;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}
- 按上述方法通过String.intern方法不断向常量池中添加变量。并时刻保持引用防止GC。最终肯定会包内存溢出的错误的。但是实际上并没有。
- 关于常量池我们这里可以简单理解成临时集中营,我们就是在这里统一生产并管理我们的变量
原因
一、解释:JDK6新增错误类型。
-
当GC为释放很小空间占用大量时间时会抛出此异常 ; 释放很小的时候我们就可以认为此次GC时失效的
-
即(Sun 官方对此的定义:超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常)。
-
一般是因为堆太小,导致异常的原因:没有足够的内存。
二、解决方案:
- 查看系统是否有使用大内存的代码或死循环。
- 可以添加JVM的启动参数来限制使用内存:-XX:-UseGCOverheadLimit
三、案例分析
- 通过查看日志我们不难发现,我们一直在想常量区新增变量。内存不够就会GC,但是我们时刻保持引用。所以GC回收不到垃圾。应征了上面的问题GC次数多回收效果小所以会报limited错误。我们添加UseGCOverheadLimit后就会报内存溢出的错误经典错误了。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space