Java和.NET这些语言,都有GC,还会有内存泄漏吗?

会发生吗?

对于java和.NET这些语言来说,都有GC进行内存的垃圾回收,因此很多同事大多都不需要考虑内存,那么是不是编写出来的应用程序最多只会发生Connection/Socket/File这些方面的资源没有释放而产生的资源泄漏,一定不会发生内存泄漏呢?

答案是否定的!在博文《系统Hotfix的时候,我们误删除了......》中,我们提到了上周三发生系统O出现内存泄漏(Memory Leak),那么我们当时是如何判定是发生了内存泄漏呢

 

定性判定:

定性判定的原则不是特别复杂,我们就是从Weblogic的Deployment管理监控中,查看Performance,通过持续的间隔采样,发现其Heap free percent的最高值在不断持续下降,在采样的时间点,进行GC后,无法回到上一个采样点的最高值,最终采样点Heap free percent趋向0,那么你就可以判定你的应用存在内存泄漏。

以上的判断对于Oracle AS和Websphere一样有效;对于.NET应用,可以跟踪进程的内存占用,同样可以进行定性判定。

 

定量判定:

那么如何进行定量判定呢?定量判定还能协助系统进行定位发现泄漏是发生在那里,由哪些对象导致的。在系统O的内存泄漏定量分析过程是一个非常不简单的过程。

 

Heap Dump是什么,如何获得?

我们需要进程的Heap Dump(进程的堆内存映射),有了这样的内存映射,才有可能进行定量分析。对于Java和.NET这些运行在VM的应用程序,进程的堆内存是由VM进行管理的,由VM的GC对堆栈进行内存分配。因此要获得这样的内存映射,不同的VM是完成不一样。

即便都是java,IBM实现的java vm和Sun实现的java vm,还有Weblogic的JRocket都是完全不同的。譬如IBM的javavm就不像另外两者,它没有Generational分代的概念,一般来讲,支持分代的VM进行Heap Dump分析会容易一些。(为什么,请读者回答)

在本文提到的系统O是运行在AIX5.3平台上,所以Weblogic9.2就是运行在IBM Javavm,这个VM如何支持Heap Dump,可以查阅相应IBM的文档。简单一点说,通过设置以下的环境变量,在运行java进程。

export IBM_HEAPDUMP=true

export IBM_HEAP_DUMP=true

然后在希望得到Heap Dump是,可以使用kill -3 <pid>来获得pid进程的内存映射。当然不同的VM有不同的方法,您自己的环境如果不同,请查阅相应的VM实现。如果没有进行以上的缺省设置,IBM javavm只在发生OOM(OutOfMemory)时,会自动进行Heap Dump。

 

采样Heap Dump是进行定量判定的基础:

在本文提到的系统O,上周三晚上,同事告诉我后,我赶到现场发现Heap free percent已经降到到0,Heap只剩下1M,系统已经发生OOM,javam自动进行一次Heap Dump。当然此时的Heap Dump已经很大了,经过zip后有700多M。

当然,我们当时还只能是怀疑存在内存泄漏,因为我们还没有经过定性分析,没有看到系统的内存泄漏过程,到底系统是以什么趋势进行泄漏,还是由于某个功能导致突发泄漏呢?因此我们在上周四进行了定性分析,通过上周四上午的分时采样,我们发现分配了接近2G的堆内存,基本上以每小时10%的比例进行泄漏,通过这样的观察,我们可以定性断定内存泄漏。上周四下午,我们开始对进程进行堆内存映射分析。我们根据上午发现的泄漏进度,选取了两个采样点进行内存采样:Heap free percent在70%和60%的时刻。


采样条件:

采样时,应该选取系统较为沉寂的时刻,如果此时系统很繁忙,吞吐量大,此时计算多,会导致采样的样本有很多需要回收的垃圾对象。另外,如果此时进行GC,会导致正在计算、运行的线程进行阻塞状态。

当我们通过系统监控,选取了系统沉寂时,连续进行两次GC,保证此时获得的样本没有过多的垃圾对象后,进行Heap Dump。然后在等待Heap free percent下降10%后,再次在沉寂时刻进行采样。

 

定量分析工具支持:

分析是需要工具,我们在分析系统O时,使用到IBM的两个分析工具,分别是命令行的HR207和图像界面的ha28。我们先打开第一个样本,从打开的内存堆映射文件,一般可以看到进程中涉及到的class数量级在万级别,涉及的object实例达到数量级百万甚至千万,涉及的数组数量级达到百万,还有其他Primitive原始内置的数据类型。

如果你面对应用级的开发,我认为一般不用考虑也不用怀疑原始类型和JDK的基础类,如果发生内存泄漏,我们可以认定一般都是由于应用系统的类型导致Leak。

我们可通过以下的过程步骤来定位怀疑泄漏的对象,从内存堆中发现类型或者对象占用大户,如果一个对象object或者相同类型Class的一批对象在两次GC之后,内存总数占用了整个堆20%以上,那么他就是你要怀疑的对象了

另外由于对象之间的引用关系Reference,还有所以的object都有getClass()获得类型定义,所以怀疑一个对象或者类型A,就可以牵扯出另一个对象或者另一个类型B

在定量分析系统O时,做到这一步,此时还只能算是怀疑而已,接着我们记下怀疑对象类型所占用的总体物理内存数,然后我们打开第二个样本,查看在Heap free percent下降了10%后,所怀疑的对象类型所占有的总体物理内存数,是不是还是在增加的。如果不是增加,那么证明我们的怀疑对象没有问题,需要寻找下一个怀疑点。

 

最后的证明:

在分析系统O时,我们还有上周三晚Heap解决极限0时的一个Heap Dump,这个Heap Dump文件很大,zip格式有700多M,在我的T500有3G内存,但是也根本无法打开,报OutofMemory错误。因此,最后没有办法,借了一台AIX,分配了5G内存,计算了一个小时后报OutofMemory错误。发狠,分配了20G内存,计算了一个小时后,打开了Heap Dump,再通过以上的判断条件和分析。发现我们怀疑的对象在系统进程接近死机极限时刻,整个2G堆空间,有一类对象共占了64%,将近1.25G内存,可想而知,它就是我们追踪到的“陈水”。

呵呵,整个过程,“他”是谁,怎么被揪出来的。你要学习台湾特侦组,顺藤摸瓜、刨根问底,逐步将怀疑对象或者类型定位到根本,才能将2630绳之以法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值