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

声明:本文禁止未经本人同意的任何形式转载!如有转载需求,可与本人通过个人资料中的电子邮箱联系。对于未经同意的转载,本人将保留进一步行动的权利!
Java EE的应用,无论部署至哪种应用服务器上,都可能遇到一些性能的问题。在此,我们将介绍一些通用的性能问题及解决方案。在性能调整和优化中,首先需要了解客户的问题。通过架构、现象等方面寻找可能影响Java EE性能的可能方面。所以本文中列举的是一些通用的问题,在实际的性能调整和优化中需要结合具体的情况来进行分析判断并做出相应调整。
  
内存溢出错误
最经常遇到的问题可能就是OutOfMemoryError了。这个错误经常缠绕着一些企业应用,让系统管理员觉得很可怕。通常,这个错误是以下一些现象的并发症:
  • 应用服务器宕机
  • 性能大幅降低
  • 表象上出现无休止重复的垃圾收集,致使正常处理中断,并还可能造成应用服务器宕机
无论是什么现象,可能都需要重启应用服务器可能才能恢复正常。
 
导致内存溢出的原因
在解决内存溢出的错误前,首先要理解这是如何产生的。如果JVM在其进程内存空间没有内存可用(包括堆的各个区域、永久内存空间),而一个进程试图创建一个新的对象实例,垃圾收集线程就开始尝试释放足够的内存空间来放置新的对象。当垃圾收集线程无法释放足够的内存时,就抛出OutOfMemoryError。
 
内存溢出错误最有可能是由于Java的内存泄露造成的。有很多关于Java内存泄露的讨论,最后的定论就是Java的内存泄露来源于对未使用对象引用的延迟释放:也就是说已经完成了对该对象的使用,但是因为还存在着一个或者多个对象引用着该对象,所以垃圾收集线程就不能收回该片内存。由该对象占有着的内存即导致了可用堆空间的流失。这样的内存泄露通常发生在Web请求阶段,例如10000个用户并发访问,而每个请求中有一个或两个存在内存泄露的对象就有可能导致服务器崩溃。更为甚者的是,一般来说,发生内存泄露的对象都不是简单的对象(例如Integer、Double),而是在堆中要占据很多“子图”的对象。例如,有可能在不经意间引用了Person的对象,而Person的对象又引用了Profile的对象,而Profile的对象又引用了好几个PerformanceReview的对象。比起Person对象占据的100字节内存来说,在这个情况下完整的“子图”对象可能占据500K或者更多的内存。
 
为了从根本上解决问题,需要判断是真实存在内存泄露还是别的内容引起的OutOfMemoryError。有如下几个判断方法:
  • 分析底层的内存统计信息
  • 检查堆增长的方式
虽然Sun和IBM的JVM不一样,JVM的调优过程却有很多相同之处。
 
SUN JVM的内存管理
Sun的JVM是有“代沟”的(开玩笑,应该说是按代分片的),也就是说在一个空间(分片)中创建的对象在真正进入长期空间前都有好几次销毁的机会。Sun的JVM被明确地分成以下几个空间(分片):
  • 新生代,包括Eden和两个生存空间(From空间和To空间)
  • 老生代
  • 永生代
 
如下图:
 
 
对象在Eden空间中创建,当Eden满后,垃圾收集线程遍历Eden中的所有对象,将活动对象拷贝至第一个生存空间,并将废对象的空间回收释放。当Eden再次充满时,垃圾收集线程就再来一遍,但将活动的对象拷贝至第二个生存空间,并将原来在第一个生存空间中的对象拷贝到第二个生存空间。如果第二个生存空间冲满后,一些留在Eden和第一个生存空间的对象就会被拷贝到老生代。当垃圾收集通过这种轻量级的方法(也称为“拷贝收集法”)不能获得足够内存的话,垃圾收集就会执行一次大规模收集,也叫“停滞收集法(stop-the-world collection)”。在这种收集法下,垃圾收集将所有线程挂起并在全堆范围内执行标记清扫收集,腾空整个新生代并准备重新开始进程。
 
拷贝收集法的运行方式图:
 
 
 
停滞收集法的运行图:
 
总的来说,对象在新生代创建,大部分都在此进行轮回,并不需要执行标记清扫收集。有一些对象上升至了老生代,因为它们活动的时间太长了,如果老生代也满了,就必须来一次标记清扫收集了。
可以看出,在Sun的实现中,老生代中的对象只能通过大规模的收集活动来收集,所以代价很高。所以需要确保对象生存的时间较短,这样在其还未进入老生代的时候就将其收集。
声明:本文禁止未经本人同意的任何形式转载!如有转载需求,可与本人通过个人资料中的电子邮箱联系。对于未经同意的转载,本人将保留进一步行动的权利!
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值