java内存泄漏分析

什么是内存泄漏?

内存泄漏就是一些已经不使用的对象还存在于内存之中且垃圾回收机制无法回收它们,导致它们常驻内存,会使内存消耗越来越大,最终导致程序性能变差。

java导出heap数据的方法

jmap -heap pid

这个是获取某java进程的heap基本信息。

jmap -dump:format=b,file=heap.bin pid

这个是dump一份heap的内存分析状态文件,然后你用eclipse mat软件来导入这个文件,然后看看给出的分析报告。

理解什么是heap(堆)

先来看一幅图,java内存模型

java内存模型

如果你用过visualvm,就会看到heap size的一个图,如下所示:

visualvm heap size

图中的最大heapsize为2G,目前已申请的heap size为125M左右,在使用中的heapsize为67M左右,这个数据你得看懂,最大heapsize是你在启动java程序时指定的,如果没指定就jvm会有一个默认的指定,指定的方式是java -Xms1024M -Xmx2048M,其中-xms表示最小的堆大小,也就是默认启动会占用的堆大小,-xmx为最大的堆大小,也就是heap堆的容量,如果你的申请不到内存了,爆出oom错误,那就是说你的heap已经用光了,你就应该检讨为啥gc没有合理回收heap,造成内存泄漏了。

实际上,你在资源管理器中看到的内存大小它是总大小,heap只是其中的一部分,heap占用1G,资源管理器中可能是1.5G。

解决方案:优化内存使用!!!

怎么优化内存使用?

首先从外部着手,要么适当增加heap size,方法使给vm增加参数-Xmx2G(表示heap堆的最大大小为2G,其实-Xmx2048M也是2G,一个意思);要么更换垃圾回收器,比如你可以换换g1垃圾回收器,方法是-XX:+UseG1GC,g1垃圾回收器是并发的回收期,回收效率很高。

然后从你的程序内不着手,分析你程序中占用内存大的,申请内存频繁的代码处是否有不必要的内存申请,我在我公司的itestin自动化录制工具中就发现了很多这样的案例。

关于使用g1gc垃圾回收器,上两幅图对比看下:

首先是默认的垃圾回收器(一般来说是串型)

默认的垃圾回收器的表现

然后是g1gc

g1gc垃圾回收期的表现

注意String!学会StringBuilder和StringBuffer

关于这三者的基础知识很多了,不赘述,给个链接自己学习:这里

我要说的就是,如果一个字符串很大,并且频繁的对它进行操作,比如replace,substring等,这样会造成很多同样大小的这样的字符串,非常消耗内存,使用StringBuilder之后,始终是对一个对象操作,不仅不需要生成额外的字符串变量而造成不必要的内存,而且可以提高执行速度!