Java内存初探

2010-03-26  赵璨 

   以前做过一些Java单元级别的性能测试,写过一些心得,范围比较局限,也比较简单,相对的也容易阅读,和大家分享一下。有时间,我可以把最近的一些项目性能测试的思路和大家分享分享。

简介:

         Java可以自动管理内存的回收,程序员不需要调用类似free(),delete()的函数释放内存,但是不意味着Java不存在内存泄漏问题。Java的内存的回收是由GC自动完成,但是GC不是万能的,当在GC能力范围之外的时候,内存泄漏就可能出现了。那什么时候超出了GC的能力范围?首先我们先了解GC能做什么,简而言之,GC可以回收的是不再被引用的对象内存如果对象在引用,就不会回收其内存。反过来思考一下,如果有仍然在引用,但是实际程序中没有起作用的对象,这时候GC就无能为力了,也就意味着内存泄漏发生了。

另外一方面,Java虚拟机在GC时与应用程序是互斥的。也就意味着当gc回收内存,会阻止所有其他线程访问程序的内存空间,这时候整个应用处于停滞状态。有个形象的术语称这段gc时间为“stop-the-world”。一般情况下,这段时间短,不易察觉。但是当内存消耗过快,gc频繁进行时,或者gc时间较长时,程序的性能会受到明显影响。

 

原理:

那么gc的频率是由什么控制的,什么时候会发生gc?这里要涉及到java虚拟机的内存分配策略,一般情况,Java虚拟机(包括sun的,ibm的等等)内存采用分代管理策略,即将内存分为年轻代、年老代和永久代,每个代上对象的生命周期不同,并执行不同的回收算法。新创建的对象在年轻代,当年轻代内存用完时,这时仍然存活“老”对象被复制到年老代,同时对年轻代进行更新,这称之为一次minor collection,也就是发生了一次gc,又叫做Scavenge GC。以此类推,当年老代的内存分完时,仍然存活的对象被复制到永久代中,这称之为major collection,也是一次gc,又或者叫做full gcFull gc会对整个堆进行整理,效率要低的多。

 

 

检测:

        内存泄漏如何侦测?现在市面有很多工具,这里不介绍这些工具的使用,大家可以到网上去搜。其实现在大多数版本的jvm都自带了gc日志,可以通过分析日志观察gc的频率和内存的消耗来推断出内存泄漏的可能性。不过gc日志格式是不一致的,例如sunibmgc日志格式就大不相同,sun的日志更加规范,可以方便通过程序来解析日志。这里以sun jdk1.5版本为例,看看如何设置gc监控:

1.       首先要启动gc监控,需要在java启动参数中增加-verbose:gc

2.       将日志输出到文件,需要增加参数-Xloggc:filename(例如-Xloggc:$BASE_HOME/logs/gc.log)。可以根据需要通过参数输出不同的gc信息。例如-XX:+PrintHeapAtGC -包括gc前后heap状况。其他的参数就不再介绍,可以上网去看。

这时大家可以就可以到logs下查看gc的日志了。

 毕竟文件里都是数据,很难看出规律行,一般有专门的gc日志分析工具,以图形化的方式展现数据。例如:

这是一个简单的full gc走势图,应该是excel做的。从图中可以看出full gc后的内存明显越来越高,full gc的频率越来越快,消耗的时间也越来越长。说明既有可能发生了内存泄漏。如果要再做定位,还需要结合jprofiler之类的工具定位到具体代码。

 

Gc的工具有个不好的地方就是,因为gc日志的格式有很多,就是同样版本的jvm,不同的参数配置也会导致gc日志大不相同。一般的工具都过于局限,经常解析不了文件。可以自己写一个gc日志分析工具。 

484°/4810 人阅读/3 条评论 发表评论

李辅炳  2010-04-14

道可道,非常道, 名可名,非常名 ,性能测试如此,人何以堪呀?


胡名海  2010-06-10

另外就是代码中String对象处理不合理时,内存消耗也是相当可观的。


付民  2010-06-10

呵呵。。学习啦


登录 后发表评论