内存泄露是指一个不再被程序使用的对象或变量一直被占据在内存中,这种情况出现会导致无法正常运行,因此作为开发人员一定要就是排查其中的原因,那java内存泄漏如何排查?下面来我们就来给大家讲解一下。
1、查看过程中的CPU和内存占用:
top –H –p 58527
2、查看服务器内存。
df -h 查看磁盘情况 du -h --max-depth=1 文件目录占用资源情况。
3、查看内存、缓存区、使用和闲置。
free -m
S0C:年轻代中第一个survivor(幸存区)的容量 (字节)
S1C:年轻代中第二个survivor(幸存区)的容量 (字节)
S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC:年轻代中Eden(伊甸园)的容量 (字节)
EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC:Old代的容量 (字节)
OU:Old代目前已使用空间 (字节)
PC:Perm(持久代)的容量 (字节)
PU:Perm(持久代)目前已使用空间 (字节)
YGC:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
4、查看执行程序信息。
jstack 2829 > 1.log grep -A 1'java.lang.Thread.State' jstack.log | wc -l
5、下载堆文件分析代码Dump。
什么原因造成内存泄漏?
1、作用域过大造成的内存泄露
(1)问题描述
public class Simple { private Object object; public void method() { object = new Object(); // ... } }
以上的代码中,我们在 method 方法中为类成员变量 object 赋值了实例化后的值,但是如果我们仅仅在这个方法中使用到了 object,那将意味着在整个类的生命周期中,object 所占用的空间虽然都不会被再次使用,但却始终无法得以回收,这就造成了内存泄露,如果 object 是一个加入了很多元素的容器,则问题将暴露的更加明显。
(2)改进
上述内存泄露代码的改进比较简单。
public class Simple { private Object object; public void method() { object = new Object(); // 使用到 object 的业务代码 object = null; } }
解决内存泄露问题的原则就是在对象不再被使用的时候立即释放相应的引用,因此在业务代码执行后,object 对象不再使用时,赋值为 null,释放他的引用就可以让 jvm 回收相应的内存了。
下面是一段 jdk8 LinkedList 的源码。
//删除指定节点并返回被删除的元素值 E unlink(Nodex) { //获取当前值和前后节点 final E element = x.item; final Nodenext = x.next; final Nodeprev = x.prev; if (prev == null) { //如果前一个节点为空(如当前节点为首节点),后一个节点成为新的首节点 first = next; } else { //如果前一个节点不为空,那么他先后指向当前的下一个节点 prev.next = next; x.prev = null; } if (next == null) { //如果后一个节点为空(如当前节点为尾节点),当前节点前一个成为新的尾节点 last = prev; } else { //如果后一个节点不为空,后一个节点向前指向当前的前一个节点 next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
可以看到,在对 x 的成员 next、item、prev 的使用结束后,都显式赋值了 null,以免他们无法被 jvm 回收,在实际开发中,很容易被忽略。
2、容器本身造成的内存泄露
(1)问题描述
Vector vec = new Vector(); for (int i = 1; i < 100; i++) { Object obj = new Object(); vec.add(obj); // 使用 obj 的相关业务逻辑 obj = null; } // 使用 vec 的相关业务逻辑
上面的代码是一个非常经典的例子,乍看之下没有任何问题,每次使用元素后,将元素引用置为 null,保证了 object 空间的回收。 但是,事实上,容器本身随着不断的扩容,也占用着非常大的内存,这是常常被忽略的,如果不将容器本身赋值为 null,则容器本身会在作用域内一直存活。
(2)改进
Vector vec = new Vector(); for (int i = 1; i < 100; i++) { Object obj = new Object(); vec.add(obj); // 使用 obj 的相关业务逻辑 obj = null; } // 使用 vec 的相关业务逻辑 vec = null;
改进方法也很简单,在不再使用容器的时候立即赋值为 null 总是最正确的。
造成java内存泄漏可能就是以上这几点原因,总之我们要知道排查方法,这样才能具体问题具体对待!最后大家如果想要了解更多java常见问答知识,敬请关注奇Q工具网。
推荐阅读: