应用代码性能诊断分析之内存泄漏

程序代码中,内存有关的问题可以分为两大类:内存访问错误和内存使用错误。

内存访问错误包括读内存错误和写内存错误。读内存错误可能让程序模块返回意想不到的结果,从而导致后续的程序模块运行异常。

内存使用错误主要是指程序模块申请的内存没有正确释放,系统可用内存逐渐减少,使程序运行逐渐减慢,直至停止。

一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的,使用完后必须显示释放该内存空间。

应用程序一般使用malloc,calloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块。

从用户使用的角度来看,内存泄露本身不会造成什么危害,一般用户可能根本不会感觉到内存泄漏的存在。但是内存泄漏是会积累的,只要执行的次数足够多,最终会耗尽所有可用内存,使软件的执行越来越慢,最后停止响应。

造成内存泄漏的原因有很多,最常见的有以下几种:

1、  分配完内存之后忘了回收。

2、  程序写法有问题,造成没办法回收。

3、  某些API函数的使用不正常,造成内存泄漏。

4、  没有及时释放。

对于如何检查程序是否内存泄漏,可以使用一些专用的内存监控工具,如MemProof 、AQTime 、 Purify 、 BundsChecker 、 JProfiler等

这里使用简单的方法,即利用Windows自带的Perfmon工具来健康程序进程的Handle Count 、Vritual Bytes 和 Working Set 3个计数器。

(1)、Handle Count记录进程当前打开的句柄个数,监视这个计数器有助于发现程序是否存在句柄类型的内存泄漏。

(2)、Vritual Bytes 记录程序进程在虚拟地址空间上使用的虚拟内存的大小,它一般总数值大于程序的Working Set。

(3)、Working Set 记录操作系统为程序进程分配的内存总量,如果这个值不断地持续增加,而Vritual Bytes却跳跃式地增加,则很可能存在内存泄漏问题。

JVM内存泄露诊断分析

对于任何应用程序来说,内存泄漏都是软件的致命伤,就JAVA来说,JAVA平台虽然有自动垃圾回收和内存托管机制,在编程上杜绝了很多内存管理的麻烦,但是同样存在内存泄漏的问题,这种内存泄露包括堆栈内存泄漏、资源内存泄漏等类型,我们真正追究到这些问题时,更应该对JAVA的JVM更多的关注。

JVM的Heap(堆)包括3部分Permanent Generation(简称PermGen)、New Generation 和 Tenured Generation(又叫Old区)

PermGen是JVM自用的区域,是内存的永久保护区,用于存放反射代理和Class,Class在被装载时就会被放到这个区域中,所以如果web服务器应用的Class相当多时,就要考虑将这一块区域放大一些。

New 和 Old区是JAVA应用的Heap区,用来存放类的实例的,其中New Generation的目标是尽可能快速的收集那些生命周期短的对象,但它以可以分为Eden Space 、Form Space、 To Space 3块,Eden Space 用于存放新创建的对象,当它满时,JVM就会执行垃圾回收GC。而Old区用于存放长寿的对象,在New区中经历了N次垃圾回收后仍然存活的对象就会被放到Old区,如那些与业务相关的对象(Http请求的Session、线程、Socket连接等)。当然,JVM执行垃圾回收是需要消耗一定的时间的。

因此,我们在优化JAVA应用平台过程中,可以设置JVM启动参数的配置,特别注意Xmn 、Xmx 、Xms 的内存大小参数。

如果因为程序代码的不合理写法,也会导致一些数据不能被收集,如何通过JVM诊断并分析性能瓶颈呢?典型情况如下:

1、  在HashMap中放置大量不用的数据,而没有及时的清理;

2、  在web应用中,页面的Session放置状态数据没有清理;

3、  在Class的Static变量中放置数据,不能被及时垃圾回收;

 

也可以通过分析JVM GC log来诊断内存泄漏的问题。

注意:

当应用程序运行过程中提示“java.lang.OutOfMemoryError PermGen space”时,如果web App下用了大量的第三方jar包,其大小 超过了JVM默认的大小,那么就会产生此问题,需要修改Tomcat下的catalina.bat,JAVA_OPTS=….

posted @ 2014-06-14 15:34  虞秀权  阅读(510)  评论(0编辑  收藏  举报