您的位置 首页 java

详解java中的OOM及 java堆溢出分析

OOM是什么?

Out of memory (OOM) 是一种操作系统或者程序已经无法再申请到内存的状态。经常是因为所有可用的内存,包括磁盘交换空间都已经被分配了。OOM的官方解释是: Understand the OutOfMemory Error Exception ,常见的OOM有以下10种(其中OOM Killer是操作系统层面的概念)

OOM分类主要分类

暂时无法在文档外展示此内容

其中OOM KIller是操作系统层面上的概念

java heap space Java 堆溢出

最常见的OOM,当堆内存没有足够的空间存放新建的对象时,就会抛出 java.lang.OutOfMemoryError:Javaheap space 错误,程序日志中可以设置关键字告警。

原因分析:

  • 请求创建一个超大对象,比如说创建一个超大的数组;
  • 内存泄漏 Memory leak,大量对象引用没有释放, JVM 无法对其自动回收,比如使用 File 等资源没有回收,比如某些代码错误,某个方法被调用一次就会占用更多的内存,随着时间的运行;
  • 过度使用 终结器 (Finalizer),该类型的对象不会通过普通GC被回收,它们进入一个特殊的终结队列,稍后处理,导致该对象没有立即被GC;
  • 超出预期的访问量/数据量,比如上游系统请求流量飙升,业务系统中的促销/秒杀活动,可以结合业务流量指标排查是否有尖状峰值。

解决方法

通常情况下,通过-Xmx参数调高JVM堆空间即可,如果不行更细致的是转存head dump 并使用MAT、 JProfiler 之类的工具进行进一步的分析。

  • 检查超大对象,哪些对象占据堆的大部分,检查创建分配堆空间的合理性,比如数据查询是否限制了结果。
  • 如果是内存泄漏,找到持有的对象,修改代码设计,对于一些连接、打开的IO文件进行关闭。
  • 对于业务峰值压力,可以增加机器资源,或者做限流降级操作。

实战案例分析

  • 代码示例
 /**
vm参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
*/public class HeapOOM {

     static  class OOMObject{}
    public static  void  main(String[] args) {
        List<OOMObject> list = new ArrayList<OOMObject>();
        while (true){
            list.add(new OOMObject());
        }
    }
}
复制代码  

-XX:+HeapDumpOnOutOfMemoryError 参数可以在虚拟机出现异常时Dump出当前内存堆转存储快照以便进行事后分析。在运行中的进程可以用jvm自带的 jmap导出堆转存快照。如:jmap -dump:live,format=b,file=

  • 运行结果
 java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid55791.hprof ...
Heap dump file created [27884840 bytes in 0.134 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.util.Arrays. copy Of(Arrays.java:3210)
        at java.util.Arrays.copyOf(Arrays.java:3181)
        at java.util.ArrayList.grow(ArrayList.java:265)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
        at java.util.ArrayList.add(ArrayList.java:462)
        at org.jvm.HeamOOM.main(HeamOOM.java:17)
复制代码  

MAT分析工具

一般生产中的出现的OutOfMemoryError需要分析出原因,一般会对java应用配置jvm参数,方便对OOM的java进程保存转存快照。

 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=.
复制代码  

有了堆转存快照文件比如前面的java_pid55791.hprof 就可以让oom问题无法遁形,当然需要顺手的分析工具而 eclipse MAT (Memory Analyzer Tool)工具就是分析Java堆内存问题的利器。

MAT是一款快速便捷且功能强大丰富的 JVM 堆内存离线分析工具。其通过展现 JVM 异常时所记录的运行时堆转储快照(Heap dump)状态,帮助定位内存泄漏问题或优化大内存消耗逻辑。可以非常直观的看到各个对象在堆空间中所占用的大小、类实例数量、对象引用关系、还能够快速的生成内存泄露报表,快速定位问题。

分析过程

使用MAT打开上面堆转存快照java_pid55791.hprof如下图:

首先看到的是一个概览页面。

第二个按钮可以打开直方图,按照类型进行分组,列出了每个类有多少实例,以及占用的内存,通过上图明显看出来基本就是OOMObject对象占用最多。通过选择引用关系,可以找出该对象被什么对象引用。

通过引用关系,发现是main线程中的ArrayList引用了。

总结

实际工作当中不会遇到经常要排查OOM的情况,这当然也与系统的业务逻辑的复杂度和用户量有关,但是掌握一些OOM知识熟悉一些工具还是有必要的,一方面通过这些工具,让我们更加了解开发语言,对于java能够更加深入的了解jvm虚拟机,通过这一次次的分析过程,了解jvm运行方式和原理,另外一方面OOM解决思路是面试中常常会问到的,对于 程序员 来说掌握OOM排查思路了解OOM分析工具更是能够在面试中取得好的结果。

文章来源:智云一二三科技

文章标题:详解java中的OOM及 java堆溢出分析

文章地址:https://www.zhihuclub.com/180027.shtml

关于作者: 智云科技

热门文章

网站地图