龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > JAVA开发 >

Java虚拟机JVM性能优化(三):垃圾收集详解(5)

时间:2014-09-20 11:09来源:网络整理 作者:网络 点击:
分享到:
4.分代垃圾收集最适合这样的应用程序,他们有很多存活时间很短的小对象,很多对象在第一轮垃圾收集周期就被回收了。对于这种应用程序分代垃圾收集

4.分代垃圾收集最适合这样的应用程序,他们有很多存活时间很短的小对象,很多对象在第一轮垃圾收集周期就被回收了。对于这种应用程序分代垃圾收集可以很好的减少碎片化,并将碎片化产生影响的时机推迟。

压缩

尽管分代垃圾收集延迟了出现碎片化和内存溢出错误的时间,然而压缩才是真正解决碎片化问题的唯一办法。压缩是指通过移动对象来释放连续内存块的垃圾收集策略,这样通过压缩为创建新对象释放了足够大的空间。

移动对象并更新对象引用是stop-the-world操作,会带来一定的消耗(有一种情况例外,将在本系列的下一篇中讨论)。存活的对象越多,压缩造成的暂停时间就越长。在剩余空间很少并且碎片化严重的情况下(这通常是因为程序运行了很长的时间),压缩存活对象较多的区域可能会有几秒种的暂停时间,而当接近内存溢出时,压缩整个堆甚至会花上几十秒的时间。

压缩的暂停时间取决于需要移动的内存大小和需要更新的引用数量。统计分析表明堆越大,需要移动的活动对象和更新的引用数量就越多。每移动1GB到2GB活动对象的暂停时间大约是1秒钟,对于4GB大小的堆很可能有25%的活动对象,因此偶尔会有大约1秒的暂停。

压缩和应用程序内存墙

应用程序内存墙是指在垃圾收集产生的暂停(例如:压缩)前可以设置的堆大小。根据系统和应用的不同,大多数的Java应用程序内存墙都在4GB到20GB之间。这也是多数的企业应用都是部署在多个较小的JVM上,而不是少数较大的JVM上的原因。让我们考虑一下这个问题:有多少现代企业的Java应用程序设计、部署是根据JVM的压缩限制来定义的。在这种情况下,为了绕过整理堆碎片的暂停时间,我们接受了更耗费管理成本的多个实例部署方案。考虑到现在硬件的大容量存储能力和企业级Java应用对增加内存的需求,这就有点奇怪了。为什么为每个实例只设置了几个GB的内存。并发压缩将会打破内存墙,这也是我下一篇文章的主题。

总结

本文是一篇关于垃圾收集的介绍性文章,帮助你了解有关垃圾收集的概念和机制,并希望能够促使你进一步阅读相关文章。这里讨论的很多东西都已经存在了很久,在下一篇中将介绍一些新的概念。例如并发压缩,目前是由Azul‘s Zing JVM实现的。它是一项新兴的垃圾收集技术,甚至尝试重新定义Java内存模型,特别是在今天内存和处理能力都不断提高的情况下。

以下是我总结出的一些关于垃圾收集的要点:

1.不同的垃圾收集算法和实现适应不同的应用程序需要,跟踪垃圾收集器是商业Java虚拟机中使用的最多的垃圾收集器。

2.并行垃圾收集在执行垃圾收集时并行使用所有资源。它通常是一个stop-the-world垃圾收集器,因此有更高的吞吐量,但是应用程序的工作线程必须等待垃圾收集线程完成,这对应用程序的响应时间有一定影响。

3.并发垃圾收集在执行收集时,应用程序工作线程仍然在运行。并发垃圾收集器需要在应用程序需要内存之前完成垃圾收集。

4.分代垃圾收集有助于延迟碎片化,但无法消除碎片化。分代垃圾收集将堆分为两个空间,其中一个空间存放新对象,另一个空间存放老对象。分代垃圾收集适合有很多存活时间很短的小对象的应用程序。

5.压缩是解决碎片化的唯一方法。多数的垃圾收集器都是以stop-the-world的方式执行压缩的,程序运行时间越久,对象引用越是复杂,对象的大小越是分布不均匀都将导致压缩时间延长。堆的大小也会影响压缩时间,因为可能有更多的活动对象和引用需要更新。

6.调优有助于延迟内存溢出错误。但是过度调优的结果是僵化的配置。在通过试错的方式开始调优之前,要确保清楚生产环境的负载、应用程序的对象类型以及对象引用的特性。过于僵化的配置很可能无法应付动态负载,因此在设置非动态值时一定要了解这样做的后果。

本系列的下一篇是:深入探讨C4(Concurrent Continuously Compacting Collector)垃圾收集算法,敬请期待!

(全文完)

精彩图集

赞助商链接