- 新上线一个业务,应该怎么选择垃圾回收器,比如G1、CMS?有没有看过Oracle官方对于G1的场景介绍,它适合什么样的场景?以下知识来源周志明的《第三版深入理解Java虚拟机》以及Oracle官网:
G1收集器常会被拿来与CMS收集器互相比较,毕竟它们都非常关注停顿时间的控制,官方资料中将它们两个并称为“The Mostly Concurrent Collectors”。
比较项 | CMS | G1 |
---|---|---|
基本结构、分代等 | Concurrent Mark Sweep,在名字上已经体现出来追求:并发收集、低停顿。工作在老年代,新生代必须配合Serial(JDK9及以后它俩不能一起了)或者ParNew收集器 | 停顿时间可控: G1把堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。也就是说,G1的新生代和老年代不再是固定的了,它们都是一系列Region(不需要连续)的动态集合。 G1收集器之所以能建立可预测的停顿时间模型,是因为它将Region作为单次回收的最小单元,这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。更具体的处理思路是让G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间,优先处理回收价值收益最大的那些Region,这也就是“Garbage First”名字的由来。 |
GC算法 | 标记-清除,会产生内存碎片 | 与CMS的“标记-清除”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,垃圾收集完成之后能提供规整的可用内存。这种特性有利于程序长时间运行,在程序为大对象分配内存时不容易因无法找到连续内存空间而提前触发下一次收集。 |
跨区域引用¹ | 相比起来CMS更简单,占用内存更少 | 就内存占用来说,虽然G1和CMS都使用卡表来处理跨代指针,但G1的卡表实现更为复杂(双向),而且堆中每个Region,无论扮演的是新生代还是老年代角色,都必须有一份卡表,明显其Region数量比传统收集器的分代数量多得多,这导致G1有着更高的内存占用负担,G1的记忆集(和其他内存消耗)可能会占整个堆容量的20%乃至更多的内存空间 |
注1:假如要现在进行一次只局限于新生代区域内的收集(Minor GC),但新生代中的对象是完全有可能被老年代所引用的,为了找出该区域中的存活对象,不得不在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的正确性,反过来也是一样。遍历整个老年代所有对象的方案虽然理论上可行,但无疑会为内存回收带来很大的性能负担。为了不因为少量的跨代引用去扫描整个老年代,只需在新生代上建立一个全局的数据结构(该结构被称为“记忆集”,Remembered Set),这个结构把老年代划分成若干小块,标识出老年代的哪一块内存会存在跨代引用。此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GCRoots进行扫描。
-
- Getting Started with the G1 Garbage Collector :
Recommended Use Cases for G1:
The first focus of G1 is to provide a solution for users running applications that require large heaps with limited GC latency. This means heap sizes of around 6GB or larger, and stable and predictable pause time below 0.5 seconds.
- Getting Started with the G1 Garbage Collector :
Applications running today with either the CMS or the ParallelOldGC garbage collector would benefit switching to G1 if the application has one or more of the following traits.
- Full GC durations are too long or too frequent.
- The rate of object allocation rate or promotion varies significantly.
- Undesired long garbage collection or compaction pauses (longer than 0.5 to 1 second)
Note: If you are using CMS or ParallelOldGC and your application is not experiencing long garbage collection pauses, it is fine to stay with your current collector. Changing to the G1 collector is not a requirement for using the latest JDK.
按照实践经验,目前在小内存应用上CMS的表现大概率仍然要会优于G1,而在大内存应用上G1则大多能发挥其优势,这个优劣势的Java堆容量平衡点通常在6GB至8GB之间。
-
为什么Concurrenthashmap里的键值对数组要用volatile修饰
-
tomcat线程池核心线程数100,最大线程数200,等待队列长度100,第101个请求是进队列还是起新的线程?A:进队列。面试官:错了,这是通用线程池,tomcat对通用线程池做了改造。相关知识见于本博----记一次线程池的maximumPoolSize的误用。Q:使用tomcat时有关注过配置吗,比如等待队列长度默认是多少。
-
Netty性能一定比tomcat好吗?什么场景更适合用Netty,什么场景用两者差不多?比如有一个场景,连接数不算很多,有几十个,但是QPS很高,达到上万。我答:Netty。
-
- Netty除了用到NIO,还有其他方面的优化吗?
-
kafka的每个leader partition在哪个位置,是由谁决定的? 以及一些牵涉到对acks与ISR的理解的问题。相关知识可见于 本博-----《专题四 服务化改造》之《第三章 【补充资料】常见消息中间件应用详解》之《第十节 Kafka》
-
- kafka有无办法做到消费的严格一次?有没有看过kafka官方的一些资料,如果要做到严格一次,有哪些建议?相关知识可见于 本博-----同程面试 之二面部分