标签:
# 1. 背景
JEP-307解决了G1垃圾回收器的一个严重的问题,截止到Java 9,G1的Full GC采用的是单线程算法,严重影响性能,无法利用到多核能力进行垃圾回收。JEP-307修复了此问题,发生Full GC时允许使用多个线程进行并行回收。
# 2. G1的简单介绍
在Java 6/7 时代,大量线上服务采用CMS垃圾回收算法,以牺牲吞吐量为代价获得较少的STW时间。但是由于CMS的特质和硬件的发展,带来了如下两个问题:
* 大堆性能较差
* 由于CMS是标记清理,导致老年代空间无可避免走向碎片化,直到并发模式失败或晋升失败,触发Full GC
为了解决CMS / Parallel的一系列问题,hotspot最早在Java SE 6 Update 14中引入G1,并在JAVA9中将默认GC算法切换为G1(JEP-248)
针对上文CMS的两个问题,G1有了相应的优化:
* 将堆切分为若干个region进行管理(如 2000个region)
* 对象疏散时,伴随着region级别的内存整理,降低了发生Full GC的概率
然而G1仅仅是降低了Full GC的概率,并不能完全避免。当并发模式失败、晋升失败、疏散失败、巨型对象分配失败时,仍然无可避免的会触发STW。而此处的Full GC由于历史原因仅使用一个线程,因此会严重的影响性能,JEP-307针对此问题专门进行了优化。
G1和CMS的详细介绍网上资料很多,此处不再赘述。
# 3. changeset 47885:5caa1d5f74c1
OpenJDK / jdk10 / hotspot 中关于G1优化的改动主要在changeset http://hg.openjdk.java.net/jdk/jdk/rev/5caa1d5f74c1
## 3.1 G1CollectedHeap
G1CollectedHeap.cpp是对G1堆管理的抽象,处理除了TLAB堆内存分配外的堆内存分配,Full GC的触发逻辑也在此接口中
2017年8月份提交的changeset 13452:4d2fded7bd7d中添加了G1SerialFullCollector.cpp,将单线程Full GC算法抽象到此文件中,并在注释中声明
```
// Temporarily make discovery by the STW ref processor single threaded (non-MT)
G1SerialFullCollector serial(scope, ref_processor_stw());
serial.prepare_collection();
serial.collect();
serial.complete_collection();
```
在JEP-307中,相关代码被修改为,除了引用处理类外,新增了mark bitmap和工作线程数入参
```
G1FullCollector collector(scope, ref_processor_stw(), concurrent_mark()->next_mark_bitmap(), workers()->active_workers());
collector.prepare_collection();
collector.collect();
collector.complete_collection();
```
## 3.2 G1FullCollector
G1FullCollector是对G1 Full GC逻辑的封装。 主要代码改动在回收(collect)阶段
```
void G1FullCollector::collect() {
// 对象标记阶段
phase1_mark_live_objects();
verify_after_marking();
deactivate_derived_pointers();
// 准备阶段
phase2_prepare_compaction();
// 指针调整阶段
phase3_adjust_pointers();
// 整理阶段
phase4_do_compaction();
}
```
使用G1CollectedHeap的线程组并行执行任务
```
void G1FullCollector::run_task(AbstractGangTask* task) {
G1CollectedHeap::heap()->workers()->run_task(task, _num_workers);
}
```
### 3.2.1 标记阶段
```
void G1FullCollector::phase1_mark_live_objects() {
// 从GC root递归遍历所有活动对象并标记
GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer());
// 多线程标记
G1FullGCMarkTask marking_task(this);
run_task(&marking_task);
G1FullGCReferenceProcessingExecutor reference_processing(this);
reference_processing.execute(scope()->timer(), scope()->tracer());
{
GCTraceTime(Debug, gc, phases) trace("Phase 1: Weak Processing", scope()->timer());
WeakProcessor::weak_oops_do(&_is_alive, &do_nothing_cl);
}
// 类的卸载和清理
if (ClassUnloading) {
GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
bool purged_class = SystemDictionary::do_unloading(&_is_alive, scope()->timer());
G1CollectedHeap::heap()->complete_cleaning(&_is_alive, purged_class);
} else {
GCTraceTime(Debug, gc, phases) debug("Phase 1: String and Symbol Tables Cleanup", scope()->timer());
// 如果不卸载类,就只清理字符串常量和符号
G1CollectedHeap::heap()->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled());
}
scope()->tracer()->report_object_count_after_gc(&_is_alive);
}
```
### 3.2.2 准备阶段
```
void G1FullCollector::phase2_prepare_compaction() {
GCTraceTime(Info, gc, phases) info("Phase 2: Prepare for compaction", scope()->timer());
// 调用prepare_compaction_common方法
prepare_compaction_ext();
}
void G1FullCollector::prepare_compaction_common() {
G1FullGCPrepareTask task(this);
run_task(&task);
// 如果没有可用region,为了避免OOM,退化为串行处理
if (!task.has_freed_regions()) {
task.prepare_serial_compaction();
}
}
```
### 3.2.3 调整阶段
```
void G1FullCollector::phase3_adjust_pointers() {
// 指针指向新地址,调整记录集
GCTraceTime(Info, gc, phases) info("Phase 3: Adjust pointers and remembered sets", scope()->timer());
G1FullGCAdjustTask task(this);
run_task(&task);
}
```
### 3.2.4 整理阶段
```
void G1FullCollector::phase4_do_compaction() {
// 根据准备阶段创建的整理队列并行整理
GCTraceTime(Info, gc, phases) info("Phase 4: Compact heap", scope()->timer());
G1FullGCCompactTask task(this);
run_task(&task);
// 如果可用region很少,为了避免OOM,退化为串行处理
if (serial_compaction_point()->has_regions()) {
task.serial_compaction();
}
}
```
# 4. 相关链接
JEP-307 http://openjdk.java.net/jeps/307
标签: 来源: https://blog.csdn.net/a860MHz/article/details/82872892
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。