java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

 

文章概述

的java虚拟机内存溢出的简要概述,复现堆内存,栈内存,方法区的运行时常量池内存等区域的溢出情况,以及上述区域发生内存溢出的判断方式和解决思路。

 

1,概述:
      IDE为eclipse,需要在运行中作为配置页签中配置虚拟机参数。

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

GC:Roots到对象之间始终可达即可。

 

注:GC Roots,java垃圾回收线程判断对象是否存活的方式,java采用的是可达性分析算法,而不是传说中的引用计数算法。

 

可达性分析算法的基本思路是当“GC Roots”的对象到其他对象是可达的,则该对象被认为是存活的,是不能被垃圾收集器回收的,反之则会被回收。

 

一个公式:操作系统内存= [Xmx]最大堆容量+ [MaxPermSize]最大方法区容量+程序计数器内存(很小,可以不计)+虚拟机进程本身耗费的内存+ [-Xss]虚拟机栈和本地方法栈内存*线程数+直接内存


java语言中被作为GC Roots的对象有:

 

虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性
引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。

 

所以书中给出的示例代码是始终不释放某对象并同时循环一直追加知道内存不足。

 

2,堆内存溢出

 

虚拟机参数:-Xms20m -Xmx20m-XX:+ HeapDumpOnOutOfMemoryError

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

结果如下:

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

可以看到Java堆空间的提示。

解决思路:

    通过内存分析工具分析转储的堆转储快照文件,如果是内存泄漏,则应该定位不该存活的对象并解决。如果是内存溢出,则需要调整内存大小。

 

内存泄漏:指本不该存活的对象还存活着,为程序问题,应修改程序。

内存溢出:指虽然出现了OutOfMemoryError异常,但内存中的对象都是必须存在的,则此时应调整内存大小。

 

3,虚拟机栈和本地方法栈溢出

虚拟机参数:-Xss 128k

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

的*Error异常

解决思路:

    一个很难想到的解决方式是在线程数量不变的情况下减少最大堆和减少栈容量,不过还是需要根据具体情况按照文章开头的公式进行分析即可

 

4,方法区和运行时常量池溢出(代码在JDK1.6中有效,原因和intern()方法的内部实现有关)

虚拟机参数:-XX:PermSize = 10M-XX:MaxPermSize = 10M

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

结果:

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

解决思路:

    因为方法区主要用于存放类的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等。

此区域在框架使用CGLIB。大量JSP文件的应用,基于OSGI的应用(因为被不同类加载器加载的同一个类,也会被认为是不同的类)等动态生成类时有可能出现内存溢出。因此应重点考虑是否是由上述原因引起。

 

5,本机直接内存
DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样。

 

解决思路:

    此区域内存溢出的明显特征是在堆转文件中不会看见明显的异常,且OOM后转储文件很小,而程序中又直接或间接使用了NIO,那就可以考虑检查一下是不是此区域引起的问题。

欢迎大家关注我的公众号号“up随想”

java虚拟机(第二版) 第二章总结 (三)-手工复现java虚拟机内存溢出(OutOfMemoryError异常)

本节完