Java内存泄漏排查

1.内存溢出和内存泄露

通俗点说:
内存溢出:申请了10个字节的空间,但是确在这个空间写入11或以上字节的数据,出现溢出。

内存泄漏:new申请了一块内存,后来很长时间都不再使用了(按理应该释放),但是因为一直被某个或某些实例所持有导致 GC 不能回收,也就是该被释放的对象没有释放。

1.1内存溢出(Out Of Memory)

产生该错误的原因主要包括:

  • JVM内存过小。
  • 程序不严密,产生了过多的垃圾。

一般情况下,在程序上的体现为:
内存中加载的数据量过于庞大,如一次从数据库取出过多数据。
集合类中有对对象的引用,使用完后未清空,使得JVM不能回收。
代码中存在死循环或循环产生过多重复的对象实体。

1.2内存泄露(Memory Leak)

指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:

  • 这些对象是可达的,即在有向图中,存在通路可以与其相连。
  • 这些对象是无用的,即程序以后不会再使用这些对象。

如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。

关于内存泄露的处理就是提高程序的健壮型,因为内存泄露是纯代码层面的问题。

1.3内存溢出和内存泄露的关系

内存泄露会最终会导致内存溢出。

相同点:都会导致应用程序运行出现问题,性能下降或挂起。

不同点:1) 内存泄露是导致内存溢出的原因之一,内存泄露积累起来将导致内存溢出。2) 内存泄露可以通过完善代码来避免,内存溢出可以通过调整配置来减少发生频率,但无法彻底避免。

2.确定频繁Full GC现象

虚拟机进程状况工具:jps(Java Virtual Machine Process Status Tool) 是 JDK 提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。

jps -l

JAVA如何看实例内存大小 java如何查看内存溢出_内存溢出


虚拟机统计信息监视工具:监视虚拟机各种运行状态信息:包括程序运行以来共发生YGC(Young GC)次数,耗时(s),发生FGC(Full GC)次数,耗时(s),总耗时GCT(GC Time)。jstat -gcutil 进程名 查询刷新时间(ms)

JAVA如何看实例内存大小 java如何查看内存溢出_内存溢出_02

3.找出导致频繁Full GC的原因

1、线上排查:使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件),查看对象的存活情况(数量和大小),可以初步分析出到底是哪个对象出现了引用未被垃圾回收收集。

jmap -histo:live 进程名

JAVA如何看实例内存大小 java如何查看内存溢出_内存溢出_03


jmap -heap 进程名

2、离线分析:把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间并且文件巨大,再从服务器上拖回本地导入工具。主要用到Histogram(展示各个类产生的实例,类似jmap -histo),Dominator Tree(展示大对象的占用率)。

jmap -dump:live,format=b,file=heap.dump-ip 进程名