OpenJDK16 ZGC 源码分析(七)GC阶段之转移集
2021/9/15 14:05:12
本文主要是介绍OpenJDK16 ZGC 源码分析(七)GC阶段之转移集,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
1. 简介
在并发处理完强引用和非强引用后,ZGC就进入了转移阶段。
本文将介绍转移阶段开始的两个小步骤,重置转移集和选择转移集。
2. 源码分析
2.1 重置转移集
在标记阶段介绍后,所有的引用都已经指向对象迁移后的新地址,ZForwardingTable中的数据已经全部失效。此时需要重置转移集,为下一轮GC做准备。
hotspot/share/gc/z/zHeap.cpp
void ZHeap::reset_relocation_set() { // 重置forwarding table ZRelocationSetIterator iter(&_relocation_set); for (ZForwarding* forwarding; iter.next(&forwarding);) { _forwarding_table.remove(forwarding); } // 重置转移集 _relocation_set.reset(); }
重置forwarding table逻辑如下:
hotspot/share/gc/z/zForwardingTable.inline.hpp
inline void ZForwardingTable::remove(ZForwarding* forwarding) { const uintptr_t offset = forwarding->start(); const size_t size = forwarding->size(); assert(_map.get(offset) == forwarding, "Invalid entry"); // 将offset后size个元素置为null _map.put(offset, size, NULL); }
转移集的reset逻辑也比较简单,就是迭代器调用forwarding的析构函数:
hotspot/share/gc/z/zRelocationSet.cpp
void ZRelocationSet::reset() { // 析构forwardings ZRelocationSetIterator iter(this); for (ZForwarding* forwarding; iter.next(&forwarding);) { forwarding->~ZForwarding(); } _nforwardings = 0; }
2.2 选择转移集
这一步主要是选择出待转移的页面,入口如下,可以看出这一步直接在ZDriver线程执行,没有并发操作。
hotspot/share/gc/z/zHeap.cpp
void ZHeap::select_relocation_set() { // 组织其他线程执行页面删除操作 _page_allocator.enable_deferred_delete(); // 注册page到转移集选择器 ZRelocationSetSelector selector; ZPageTableIterator pt_iter(&_page_table); for (ZPage* page; pt_iter.next(&page);) { if (!page->is_relocatable()) { // 本次GC开始后分配的page,无需转移 continue; } if (page->is_marked()) { // 添加存活page selector.register_live_page(page); } else { // 添加空page selector.register_empty_page(page); // 回收空page free_empty_pages(&selector, 64 /* bulk */); } } // 回收空page free_empty_pages(&selector, 0 /* bulk */); // page注册完毕,其他线程可以删除page了 _page_allocator.disable_deferred_delete(); // 选择转移集 selector.select(); _relocation_set.install(&selector); // 初始化forwarding table ZRelocationSetIterator rs_iter(&_relocation_set); for (ZForwarding* forwarding; rs_iter.next(&forwarding);) { _forwarding_table.insert(forwarding); } // Update statistics ZStatRelocation::set_at_select_relocation_set(selector.stats()); ZStatHeap::set_at_select_relocation_set(selector.stats()); }
具体的选择逻辑如下:
hotspot/share/gc/z/zRelocationSetSelector.cpp
void ZRelocationSetSelectorGroup::select() { if (is_disabled()) { return; } EventZRelocationSetGroup event; // 只有中小页面可以转移,因为large page只包含一个对象 if (is_selectable()) { // 实际的选择函数 select_inner(); } // Send event event.commit(_page_type, _stats.npages(), _stats.total(), _stats.empty(), _stats.relocate()); } // 计算出可回收页面,并计算出转移回收页面上的存活对象所需要的空间 void ZRelocationSetSelectorGroup::select_inner() { // 存活页面的数量 const int npages = _live_pages.length(); int selected_from = 0; int selected_to = 0; size_t selected_live_bytes = 0; size_t selected_forwarding_entries = 0; size_t from_live_bytes = 0; size_t from_forwarding_entries = 0; // 按页面的活跃对象字节数排好序 // 升序排序 semi_sort(); // 添加活跃页面到候选转移集 for (int from = 1; from <= npages; from++) { ZPage* const page = _live_pages.at(from - 1); // 需要转移的字节数 from_live_bytes += page->live_bytes(); from_forwarding_entries += ZForwarding::nentries(page); // 计算转移后对象需要的页面数 const int to = ceil((double)(from_live_bytes) / (double)(_page_size - _object_size_limit)); // 只有页面垃圾大于25%的页面,才会添加到转移集 const int diff_from = from - selected_from; const int diff_to = to - selected_to; const double diff_reclaimable = 100 - percent_of(diff_to, diff_from); // ZFragmentationLimit默认为25% if (diff_reclaimable > ZFragmentationLimit) { selected_from = from; selected_to = to; selected_live_bytes = from_live_bytes; selected_forwarding_entries = from_forwarding_entries; } log_trace(gc, reloc)("Candidate Relocation Set (%s Pages): %d->%d, " "%.1f%% relative defragmentation, " SIZE_FORMAT " forwarding entries, %s", _name, from, to, diff_reclaimable, from_forwarding_entries, (selected_from == from) ? "Selected" : "Rejected"); } } bool ZRelocationSetSelectorGroup::is_selectable() { // 只有中小页面可以转移,因为large page只包含一个对象 return _page_type != ZPageTypeLarge; }
3. 总结
本文介绍了转移阶段开始的两个小步骤,重置转移集和选择转移集,后文将继续介绍并发转移的过程。
这篇关于OpenJDK16 ZGC 源码分析(七)GC阶段之转移集的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南