JVM的OOM分析总结

一、heap堆内存溢出可以分为两种情况:
1、内存泄漏(Memory Leak)
如果是内存泄漏,可以进一步通过工具查看泄漏对象到GC ROOTS的引用链。于是就能找到泄漏对象是通过怎么样的路径与GC Roots相关联并导致垃圾收集器无法自动回收他们的。掌握了泄漏对象的类型信息及GC Roots引用链的信息,就可以比较准确地定位出泄漏代码的位置。
2、内存溢出(Memory overflow)
如果不是内存泄漏,换句话说,就是内存中的对象确实都还必须活着,那就应当检查虚拟机的堆参数(-Xmx 与 -Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

二、栈内存溢出(-Xss):
1、如果线程请求的深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。如果栈的深度小或者栈针的容量比较大、用递归时,都可能引起。
2、如果是虚拟机在扩展时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。当使用多线程的时候,需要注意。

三、方法区和运行时常量池溢出(-XX:PermSize -XX:MaxPermSize)
运行时常量池:运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述外,还有一项信息是常量池(Constant Pool TABLE),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。方法区限定大小后,就间接的限制其中常量池的容量。
1、常量池中存放大量的String对象,并保持对这些对象的引用,避免Full GC回收常量池,就会产生OutOfMemoryError异常,后面跟的提示信息是“PermGen space”,说明运行时常量池属于方法区。
2、方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。当产生大量的类去填充满方法区,就会溢出

四、本机直接内存溢出(-MaxDirectMemorySize):
DirectMemory容量可通过MaxDirectMemorySize指定,如果不指定,则默认与java堆最大值一样。虽然DirectMemory内存溢出时也会抛出内存溢出异常,但它抛出的异常时并没有真正向操作系统申请内存分配,于是手动抛出异常。一个明显的特征是在Heap Dump文件中不会看见明显的异常,如果发现OOM之后Dump文件很小,而且程序中又直接或者间接使用了NIO,那就可以考虑检查一下是不是这方面的原因。

如果有不同见解,可以多多交流!

posted @ 2018-11-17 16:40  江城印象  阅读(1692)  评论(0编辑  收藏  举报