OutOfMemoryError这算是高级的异常吗

「这是我参与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