Java垃圾回收精粹分4个部分,本篇是第4部分。在第4部分里介绍了G1收集器、其他并发收集器以及垃圾收集监控和调优。

Garbage First (G1) 收集器

G1 (-XX:+UseG1GC)收集器是一个新的收集器。G1随Java 6发布,在Java 7U4中得到正式支持。它是一个部分并发的收集算法,通过尝试小量增加全局暂停的方式压缩年老区,将FullGC降到最低。因为碎片引起的FullGC正是CMS的一大麻烦。G1也是分代收集器,但是它与其他收集器使用不同的堆组织方式。根据不同的用途,G1将堆划分为一大批(约2000个)固定大小的区,而不是相同用途的堆连续在一起。

G1并发地标记区域以跟踪区域之间的引用,同时关注收集区域中的最大空闲空间。这些区域在递增的全局暂停中被收集,存活的对象被剪切到一个空的区域里面,这样整个过程就是压缩的。在同一个周期里收集的区域叫做Collection Set。

译注:G1会跟踪各个区域中的垃圾堆积的价值大小、回收后获得的空间大小以及回收所需时间,在后台维护一个优先列表。每次根据允许的收集时间,优先回收价值最大的区域,也就是Garbage-First名称的来由。

超过区域大小50%的对象会在大区域里分配,其大小可以达到当前区域大小的数倍大。G1收集和分配大对象操作的开销非常大,更加悲剧的是,目前还没有任何优化措施。

任何压缩收集器所遇到的挑战不是去移动对象,而是更新这些对象的引用。如果一个对象被许多个区域引用,那么更新这些引用肯定会比移动对象更加耗时。G1通过“记录集(Remembered Sets)” 跟踪区域中被其他区域引用的那些对象。记忆集是一些卡片的集合,这些卡片上标记着更新信息。如果记忆集变大,那么G1就会显著变慢。当从一个区域转移对象到另一区域时,由此引发的全局暂停时间与需要扫描和更新引用区域的数量成正比。

维护记录集会增加次要回收的成本,结果导致花费的时间比并行旧生代收集器和CMS收集器中次要回收暂停的时间更久。

G1是目标驱动的,可以通过“–XX:MaxGCPauseMillis=<n>”设置延迟时间,默认是200ms。该参数只会尽可能影响每个周期的工作量,但是不保证最终效果。设置为几十毫秒大多是徒劳的,而且几十毫秒也不是G1关注的目标。

如果你的应用程序可以容忍暂停0.5-1.0秒的增量压缩时间,而且此应用拥有一个会逐渐碎片化的堆,那么G1会是通用的收集器的一个很好选择。最坏情况是碎片引起的暂停,我们之前在CMS那儿也见过。G1 倾向于减少这种暂停的频率,因为那会花费额外的次要回收和对年老代的增量压缩。大部分的暂停被限制在区域层面而不是整个堆的压缩。

与CMS一样,G1也会因为无法保证晋升率而失败,最终求助于全局暂停的FullGC。就像CMS存在“并发模式失败”一样,G1也可能遭遇转移失败,在日志中看到“到达空间溢出(to-space overflow)”。没有空余区域可供对象转移进去,跟晋升失败类似。如果发生这种情况,试试使用更大的堆、更多的标记线程,但在某些情况下,需要应用程序作出改变以减少分配比率。

G1的一个有挑战性的问题是,如何处理好高关注率的对象和区域。 当区域里的存活对象没有被其他区域大量引用时,增量的全局暂停进行压缩会很高效。如果一个对象或者区域被大量引用了,记录集将会相应地变大,并且G1会避免收集这些对象。最终没有办法,只能频繁地使用中等长度的暂停时间来压缩堆大小。

其他并发收集器

CMS和G1通常被称为并发性最好的收集器。然而当你观察整个工作过程,很显然地,新生代、晋升、甚至多数年老代的工作根本不是并发的。CMS对年老代来说是并发性最好的算法,G1更像是全局暂停的增量收集器。CMS和G1都明显地拥有规律的全局暂停发生,并且在最坏情况下他们不适合严格的低延迟应用,比如金融交易或用户交互界面。

其他可用的的收集器还有:Oracle JRockit Real Time、IBM WebSphere Real Time、 Azul Zing。JRockit和Websphere收集器大多数情况下在延迟上控制得比CMS和G1好,但是在大多数情况下它们有吞吐量的限制,并且会有明显的全局暂停。Zing是洒家知道的一款能对所有代都真正并发收集和压缩,同时保持了高吞吐率的Java收集器。Zing确实有一些亚毫秒级的全局暂停,但这些是在与存活对象集大小无关的收集周期里完成。

JRockit Real Time在堆大小合适时,可以将暂停时间控制在几十毫秒,但是偶尔也会失败转为完全压缩暂停。WebSphere RealTime通过约束分配率和存活集的大小,可以将暂停时间控制在几毫秒。Zing在所有阶段并发以保证高分配率,从而实现亚毫秒级的暂停,包括次要收集阶段。无论堆大小,Zing都能够保持行为的一致性。如果需要保证程序的吞吐量或者需要控制对象模型状态,用户完全可以添加更大的堆而不用担心增加暂停时间。

对于所有的并发收集器来说,如果你关注延迟,就必须牺牲吞吐量换取空间。依据并发收集器的效率,你可能放弃一点点的吞吐量,但是总能显著地增加空间。如果真正实现了并发很少会发生全局暂停,但是这就需要更多CPU内核来支持并发操作和维持吞吐量。

注意:当分配的空间足够时,所有的并发收集器倾向于更高效地运行。第一条经验,你应该预算至少两到三倍存活集大小以确保高效地操作。然而,大量并发操作所需的空间随着应用程序的吞吐量以及与之相关的对象分配和晋升率增长而增加。因此,对于高吞吐量的应用,维持较高的存活集的堆大小比率很有必要。鉴于今天的服务器拥有巨大的内存空间,这些不成问题。

垃圾收集监控和调优

要理解你的应用程序和垃圾收集器是如何工作的,启动JVM时要至少添加以下参数:

1
2
3
4
5
6
7
-verbose:gc
-Xloggc:
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime

然后加载日志到像Chewiebug这样的工具进行分析。

为了看到GC动态运行,请启动JVisualVM并且安装Visual GC插件。接下来你就能看见你的应用程序的GC,行为如下图:


要理解应用堆GC的要求,你需要一个有代表性且可以重复执行的负载测试。随着你堆每个收集器如何工作的理解,通过不同的配置运行负载测试,直至达到你期望的吞吐量和延迟。从最终用户的视角来看,测量延迟是最重要的。可以通过捕获每个测试请求的响应时间,将之记在直方图上,比如HdrHistogram或者Disruptor Histogram,这样你就能分析出更多东西。如果延迟峰值超出可接受范围,可以尝试关联GC日志来判断是否是GC出了问题。还有可能是其他问题导致的延迟高峰。另一个值得考虑的工具是jHiccup,可以用它来跟踪JVM暂停并且可以和系统合为一个整体。使用jHiccup测量空闲系统几个小时,通常会让你得到一个令人惊讶的结果。

如果延迟峰值由GC导致,那么你可以看看CMS或G1看是否可满足这个延迟目标。有时这是不可能的,因为高分配率和晋升率与低时延的要求是冲突的。GC调优是一个高技巧性的锻炼,常常需要修改程序以减少对象分配率或对象生命周期。如果需要权衡时间、GC资源优化和应用程序的修改及精通,那么可能必需购买商业的并发压缩JVM,比如JRockit Real Time 和 Azul Zing。

原文链接: mechanical-sympathy 翻译: ImportNew.com邢 敏
译文链接: http://www.importnew.com/8352.html

Java垃圾回收精粹 — Part4的更多相关文章

  1. Java垃圾回收精粹 — Part3

    Java垃圾回收精粹分4个部分,本篇是第3部分.在第3部分里介绍了串行收集器.并行收集器以及并发标记清理收集器(CMS). 串行收集器(Serial Collector) 串行收集器是最简单的收集器, ...

  2. Java垃圾回收精粹 — Part2

    Java垃圾回收精粹分4个部分,本篇是第2部分.在第2部分里介绍了Hotspot中的堆结构.对象分配以及次要回收. Hotspot中的堆结构 理解不同的收集器的工作方式,是探讨Java堆结构如何支持分 ...

  3. Java垃圾回收精粹 — Part1

    Java垃圾回收精粹分4个部分,本篇是第1部分.在第1部分里介绍了权衡点.对象生命周期以及全局暂停事件. 串行.并行.并发.CMS.G1.年轻代(Young Gen).新生代(New Gen).旧生代 ...

  4. 【转载】Java垃圾回收机制

    原文地址:http://www.importnew.com/19085.html Java垃圾回收机制 说到垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联 ...

  5. 【转】深入理解 Java 垃圾回收机制

    深入理解 Java 垃圾回收机制   一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...

  6. 深入理解java垃圾回收机制

    深入理解java垃圾回收机制---- 一.垃圾回收机制的意义 Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再 ...

  7. Java GC系列(2):Java垃圾回收是如何工作的?

    本文由 ImportNew - 伍翀 翻译自 javapapers. 目录 垃圾回收介绍 垃圾回收是如何工作的? 垃圾回收的类别 垃圾回收监视和分析 本教程是为了理解基本的Java垃圾回收以及它是如何 ...

  8. Java GC系列(1):Java垃圾回收简介

    本文由 ImportNew - 好好先生 翻译自 javapapers. Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Ja ...

  9. Java垃圾回收介绍(译)

    在Java中,对象内存空间的分配与回收是由JVM中的垃圾回收进程自动完成的.与C语言不同的是,在Java中开发者不需要专门为垃圾回收写代码.这是使Java流行的众多特征之一,也帮助了程序员写出了更好的 ...

随机推荐

  1. python 爬图

    利用bs库进行爬取,在下载html时,使用代理user_agent来下载,并且下载次数是2次,当第一次下载失败后,并且http状态码是500-600之间,然后会重新下载一次 soup = Beauti ...

  2. (三)Spring 之AOP 详解

    第一节:AOP 简介 AOP 简介:百度百科: 面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是软件开发中的一个热点,也是Spring框架中的一个 ...

  3. asyncio的简单了解

    asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio的编程模型就是一个消息循环.我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要 ...

  4. 【hdoj_1133】Buy the Ticket(卡特兰数+大数)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1133 题目的意思是,m个人只有50元钱,n个人只有100元整钱,票价50元/人.现在售票厅没钱,只有50元 ...

  5. 【转】EventBus 3.0使用详解

    原文:https://www.jianshu.com/p/f9ae5691e1bb 01 前言 当我们进行项目开发的时候,往往是需要应用程序的各组件.组件与后台线程间进行通信,比如在子线程中进行请求数 ...

  6. html5.2新特性【长期更新】

    先来说几个新定义: 1.p标签里只能是文字内容,不能在里面使用浮动,定位这些特性了.语义化加强,p标签就是文字标签. 2.legend以前只能是纯文本,新版可以加标签了,很爽吧. <fields ...

  7. 一次压力测试Loadrunner经验分享

    一次压力测试Loadrunner经验分享 http://blog.csdn.net/lxlmj/article/category/553431 loadrunner测试socketstcpserver ...

  8. iOS 9音频应用播放音频之控制播放速度

    iOS 9音频应用播放音频之控制播放速度 iOS 9音频控制播放速度 iOS9音频文件在播放时是以一定的速度进行的.这个速度是可以进行更改的,从而实现iOS9音频文件的快速播放和慢速播放功能.要实现i ...

  9. [转]iOS开发new与alloc/init的区别

    1.在实际开发中很少会用到new,一般创建对象咱们看到的全是[[className alloc] init] 但是并不意味着你不会接触到new,在一些代码中还是会看到[className new], ...

  10. Redis学习篇(十二)之管道技术

    通过管道技术降低往返时延 当后一条命令不依赖于前一条命令的返回结果时,可以使用管道技术将多条命令一起 发送给redis服务器,服务器执行结束之后,一起返回结果,降低了通信频度.