深入JVM读书笔记(二)——OOM各种情况

时间:2023-02-11 20:56:15

Java虚拟机内存有好几个运行时数据区会有OOM的异常,如果能够区分根据报错区分出是哪些区域报出来的异常,会更便于定位问题,解决问题。

1.Java堆溢出

         原因:由于不断创建对象实例,当对象数量达到了最大堆的容量限制后产生内存溢出异常。

         现象:java.lang.OutOfMemoryError: Java heap space

         解决方法:

         1)首先确认是内存泄露(Memory Leak)还是内存溢出(Memory Overflow);

         2)如果是内存泄漏引起的,查看GC Roots引用链,找出为什么无法被垃圾回收的原因;

         3)如果是内存溢出,检查虚拟机的堆参数(-Xmx最大值和-Xms最小值),对比物理内存看是否可以调大;

 

2.虚拟机栈和本地方法栈溢出

由于Hot Spot虚拟机的实现是不区分两者的,所以可以通过-Xss参数来设定栈容量。

java.lang.*Error:

  原因:在单线程下,虚拟机栈容量太小或者定义了大量的本地变量,会抛出SO;

  解决方法:增大虚拟机栈容量;

java.lang.OutOfMemoryError: unable to create new native thread

  原因:在多线程下,大量创建新线程,会抛出OOM,每个线程的栈分配的内存越大,越容易产生;

  解决方法:减少线程产生、降低最大堆、减少栈容量;

 

3.运行时常量池溢出

         原因:代码在运行时创建了大量的常量,超出了常量池上限;

         现象:java.lang.OutOfMemoryError: PermGen space

                            at java.lang.String.intern(Native Method)

   解决方法:通过修改-XX:PermSize和-XX:MaxPermSize参数来修改方法区大小,从而修改常量池大小;

 

4.方法区溢出

         原因:在运行时,ClassLoader动态加载了大量的Class信息,超出方法区上限;

         现象:java.lang.OutOfMemoryError: PermGen space

                            at java.lang.ClassLoader.defineClass(Native Method)

   解决方法:通过修改-XX:PermSize和-XX:MaxPermSize参数来修改方法区大小;

 

总之,引起OOM原因有很多,但是如果能够清楚了解底层内存存储的原理,就能够根据报错信息快速定位OOM报错原因,从而解决问题!

下面罗列一些经常用到的jvm参数:

所有用到的JVM启动参数:
-Xss2M       设置JVM栈内存大小
-Xms20M    设置堆内存初始值
-Xmx20M    设置堆内存最大值
-Xmn10M    设置堆内存中新生代大小
-XX:SurvivorRatio=8  设置堆内存中新生代Eden 和 Survivor 比例
-XX:PermSize=10M  设置方法区内存初始值
-XX:MaxPermSize=10M  设置方法区内存最大值
-XX:MaxDirectMemorySize=10M 设置堆内存中新生代大小