`

Java EE应用中的性能问题解决方案 — 第一部分 内存溢出的解决办法及JVM内幕(D)

阅读更多

 声明:本文禁止未经本人同意的任何形式转载!如有转载需求,可与本人通过个人资料中的电子邮箱联系。对于未经同意的转载,本人将保留进一步行动的权利

可能较多数量的对内存泄露的错误判断来自会话部分。会话部分并不会泄露任何内存。它消耗内存,表面上很像内存泄露,但最终会话内存还是会被回收的。如果应用服务器内存溢出,要想知道这个溢出情况是由于内存泄露引起的还是由于对会话管理不善造成的,最好的办法是停止对应用服务器的请求,直至会话都失效后来观察内存是否已经被回收。显然,在生产环境下不太可能做这样的监控,但使用这种办法来判断到底是因为会话内容太多还是因为内存泄露造成内存溢出是肯定不会有问题的。
 
总的来讲,如果应用中过分使用了会话,则正确的解决之道就是调整应用的会话应用来降低内存的开销。以下办法可以将超大会话的影响降到最低:
加大支持会话的堆尺寸
减少会话失效时间
 尺寸越大的堆就会花更长的垃圾收集时间,所以并不是最佳的解决方案,但是总比内存溢出强些。增加堆的尺寸以支持会话在其生命周期内驻留可能需要足够多的内存,计算方法是:活动用户的会话内存量+会话失效周期内的会话内存量。如果业务逻辑允许,降低会话失效时间可能是更好的选择。
 
总之,以下是按照优先级排列的解决步骤:
调整应用减少会话内存用量
鼓励最终用户及时登出系统
强制降低会话失效时间
增大堆尺寸
 
但是,在应用范围内的变量(application)、静态变量和长期生存的类都是真正需要在内存分析器中分析内存泄露的点。
 
永生代异常
JVM中永生代在处理内存中的用途往往被误解了。堆本身只携带类实例,但在JVM能真正创建堆上的类实例时,必须先要将字节码(.class)加载到处理内存中来。这样才能使用这些字节码在堆中创建类对象。JVM把类的不同版本的字节码存放在永生代中。下图即是永生代和堆的关系图。永生代在JVM处理内存的内部,并不属于堆。
 

 
通常,可能希望永生代能足够大,大得能容纳应用中所有的类,因为这些类显然会被实例化,而且从磁盘系统里面读取的代价要比从内存中读取的代价昂贵。JVM使用-noclassgc调优选项来确保类不会从永生代中卸载。该选项不让垃圾收集在永生代中运行。这个选项固然好,但有一个问题就是如果永生代满了会如何?根据我的观察,JVM会检查永生代来确定其是否需要内存,因此就会触发一个大规模的垃圾回收。但垃圾回收清理堆中的内存,如果加上了-nocloassgc,就不会动永生代的空间,所以这也是徒劳无果的。完成垃圾回收后,JVM又去查看永生代空间,发现还是没有空间,于是就一遍一遍又一遍地执行垃圾回收!
 
我第一次遇到这个问题时,就是系统的性能极端低下,经过一段时间后就会内存溢出。经过对详细垃圾回收日志、堆空间利用和处理内存利用图,很快就发现堆中的情况正常,但是处理内存溢出了。该系统中有数千个类和JSP页面,再加上-noclassgc选项,永生代就产生了异常的情况。做调优处理时可以将永生代空间加大,并去掉-noclassgc的JVM选项。
 

 
如上图所示,当永生代空间充满后,就会触发大规模的垃圾回收,将Eden和生存空间的对象清理到老生代中去。但如果加上-noclassgc选项,则不会对永生代的空间进行回收。

未完待续……
Java EE应用中的性能问题解决方案参考资料下载
声明:本文禁止未经本人同意的任何形式转载!如有转载需求,可与本人通过个人资料中的电子邮箱联系。对于未经同意的转载,本人将保留进一步行动的权利!


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/BU_BetterYou/archive/2008/05/30/2495265.aspx

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics