GC在HotSpot中的地位举足轻重。JDK9为止提供了四种收集器:Serial,CMS,Parallel,G1。按机器规模,分代类型,吞吐量,延时,CPU利用率等,结合不同的算法,每种收集器都有各自适用的使用场景,同时衍生出多种GC组合配置。今天来看Serial收集器。
- Serial收集器属于分代GC收集器。
- 年轻代主要算法为复制算法,老年代主要算法为标记压缩算法。
- Serial和SerialOld都是单线程GC。特点是需要STW。
- 适用于响应时间要求不高的桌面应用或开发调试环境。
一. Serial收集器初始化
使用 -XX:+UseSerialGC 切换到串行收集器模式,断点调试
hotspot/src/share/vm/runtime/init.cpp
jint init_globals() { jint status = universe_init();}
hotspot/src/share/vm/memory/universe.cpp
jint universe_init() { jint status = Universe::initialize_heap();}
hotspot/src/share/vm/memory/universe.cpp
jint Universe::initialize_heap() {
_collectedHeap = create_heap();
status = _collectedHeap->initialize();
}
hotspot/src/share/vm/memory/universe.cpp
使用UseSerialGC策略创建堆
CollectedHeap* Universe::create_heap() {
if (UseParallelGC) {
return Universe::create_heap_with_policy<ParallelScavengeHeap, GenerationSizer>();
} else if (UseG1GC) {
return Universe::create_heap_with_policy<G1CollectedHeap, G1CollectorPolicy>();
} else if (UseConcMarkSweepGC) {
return Universe::create_heap_with_policy<GenCollectedHeap, ConcurrentMarkSweepPolicy>();
} else if (UseSerialGC) {
return Universe::create_heap_with_policy<GenCollectedHeap, MarkSweepPolicy>();
}
}
hotspot/src/share/vm/memory/universe.inline.hpp
策略模板函数
template <class Heap, class Policy>
CollectedHeap* Universe::create_heap_with_policy() {
Policy* policy = new Policy(); //创建收集策略 MarkSweepPolicy是GenCollectorPolicy的一种
policy->initialize_all();
return new Heap(policy); //创建分代堆具体来说就是GenCollectedHeap
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
GenCollectedHeap是CollectedHeap的一种,CardTableRS处理老年代对年轻代的跨代引用
jint GenCollectedHeap::initialize() {
// Allocate space for the heap.
char* heap_address; //堆空间地址
ReservedSpace heap_rs; //映射堆空间
size_t heap_alignment = collector_policy()->heap_alignment(); //堆大小
heap_address = allocate(heap_alignment, &heap_rs); //分配堆空间
//MemRegion到ReservedSpace的映射
initialize_reserved_region((HeapWord*)heap_rs.base(), (HeapWord*)(heap_rs.base() + heap_rs.size()));
//使用MemRegion为CardTableRS分配一块内存
_rem_set = collector_policy()->create_rem_set(reserved_region());
set_barrier_set(rem_set()->bs());
//年轻代空间
ReservedSpace young_rs = heap_rs.first_part(gen_policy()->young_gen_spec()->max_size(), false, false);
//初始化年轻代空间
_young_gen = gen_policy()->young_gen_spec()->init(young_rs, rem_set());
//老年代空间
heap_rs = heap_rs.last_part(gen_policy()->young_gen_spec()->max_size());
ReservedSpace old_rs = heap_rs.first_part(gen_policy()->old_gen_spec()->max_size(), false, false);
//初始化老年代空间
_old_gen = gen_policy()->old_gen_spec()->init(old_rs, rem_set());
return JNI_OK;
}
hotspot/src/share/vm/gc/shared/generationSpec.cpp
创建对应的收集器分代类型,Serial收集器对应DefNewGeneration和TenuredGeneration分代
#if INCLUDE_ALL_GCS
#include "gc/cms/concurrentMarkSweepGeneration.hpp"
#include "gc/cms/parNewGeneration.hpp"
#endif // INCLUDE_ALL_GCS
Generation* GenerationSpec::init(ReservedSpace rs, CardTableRS* remset) {
switch (name()) {
case Generation::DefNew:
return new DefNewGeneration(rs, init_size());
case Generation::MarkSweepCompact:
return new TenuredGeneration(rs, init_size(), remset);
#if INCLUDE_ALL_GCS
case Generation::ParNew:
return new ParNewGeneration(rs, init_size());
case Generation::ConcurrentMarkSweep: {
ConcurrentMarkSweepGeneration* g = NULL;
g = new ConcurrentMarkSweepGeneration(rs, init_size(), remset);
g->initialize_performance_counters();
return g;
}
#endif // INCLUDE_ALL_GCS
}
hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
创建年轻代,DefNewGeneration是Generation的一种,ContiguousSpace继承CompactibleSpace间接继承自Space
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
const char* policy)
: Generation(rs, initial_size),
_preserved_marks_set(false /* in_c_heap */),
_promo_failure_drain_in_progress(false),
_should_allocate_from_space(false)
{
//初始化MemRegion
MemRegion cmr((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
GenCollectedHeap* gch = GenCollectedHeap::heap();
//初始化卡表CardTableModRefBS
gch->barrier_set()->resize_covered_region(cmr);
//创建eden,from,to三块连续空间
_eden_space = new ContiguousSpace();
_from_space = new ContiguousSpace();
_to_space = new ContiguousSpace();
//计算空间尺寸
uintx alignment = gch->collector_policy()->space_alignment();
uintx size = _virtual_space.reserved_size();
_max_survivor_size = compute_survivor_size(size, alignment);
_max_eden_size = size - (2*_max_survivor_size);
//计算三块空间的边界
compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
_old_gen = NULL;
//晋升到老年代阈值
_tenuring_threshold = MaxTenuringThreshold;
_pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize;
//计时器
_gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer();
}
hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp
创建老年代,tenuredGeneration是CardGeneration的一种
TenuredGeneration::TenuredGeneration(ReservedSpace rs,
size_t initial_byte_size,
CardTableRS* remset) :
CardGeneration(rs, initial_byte_size, remset)
{
HeapWord* bottom = (HeapWord*) _virtual_space.low();
HeapWord* end = (HeapWord*) _virtual_space.high();
_the_space = new TenuredSpace(_bts, MemRegion(bottom, end));
_the_space->reset_saved_mark();
_gc_stats = new GCStats();
const char* gen_name = "old";
GenCollectorPolicy* gcp = GenCollectedHeap::heap()->gen_policy();
// Generation Counters -- generation 1, 1 subspace
_gen_counters = new GenerationCounters(gen_name, 1, 1,gcp->min_old_size(), gcp->max_old_size(), &_virtual_space);
_gc_counters = new CollectorCounters("MSC", 1);
_space_counters = new CSpaceCounters(gen_name, 0,_virtual_space.reserved_size(),_the_space, _gen_counters);
}
hotspot/src/share/vm/gc/shared/cardGeneration.cpp
CardGeneration::CardGeneration(ReservedSpace rs,
size_t initial_byte_size,
CardTableRS* remset) :
Generation(rs, initial_byte_size), _rs(remset),
_shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
_used_at_prologue()
{
HeapWord* start = (HeapWord*)rs.base(); //起始
size_t reserved_byte_size = rs.size(); //空间大小
MemRegion reserved_mr(start, heap_word_size(reserved_byte_size));
//BlockOffsetSharedArray辅助提升对象起始地址查找效率
_bts = new BlockOffsetSharedArray(reserved_mr,heap_word_size(initial_byte_size));
MemRegion committed_mr(start, heap_word_size(initial_byte_size));
_rs->resize_covered_region(committed_mr);
_min_heap_delta_bytes = MinHeapDeltaBytes;
_capacity_at_prologue = initial_byte_size;
_used_at_prologue = 0;
}
hotspot/src/share/vm/gc/shared/generation.cpp
Generation::Generation(ReservedSpace rs, size_t initial_size) :
_ref_processor(NULL) {
//初始化虚空间,ReservedSpace到VirtualSpace的映射
_virtual_space.initialize(rs, initial_size)
//VirtualSpace到MemRegion的映射
_reserved = MemRegion((HeapWord*)_virtual_space.low_boundary(),
(HeapWord*)_virtual_space.high_boundary());
}
二.分代
hotspot/src/share/vm/gc/shared/generation.hpp
分代基类提供了一组虚函数,包括对象分配,对象提升,内存回收,压缩,对象遍历等,模板设计模式具体算法由各子类提供
class Generation: public CHeapObj<mtGC> {
//
virtual HeapWord* allocate(size_t word_size, bool is_tlab) = 0;
virtual HeapWord* par_allocate(size_t word_size, bool is_tlab) = 0;
virtual oop promote(oop obj, size_t obj_size);
virtual oop par_promote(int thread_num, oop obj, markOop m, size_t word_sz);
virtual void collect(bool full,bool clear_all_soft_refs,size_t word_size,bool is_tlab) = 0;
virtual HeapWord* expand_and_allocate(size_t word_size, bool is_tlab, bool parallel = false) = 0;
// Mark sweep support phase2
virtual void prepare_for_compaction(CompactPoint* cp);
// Mark sweep support phase3
virtual void adjust_pointers();
// Mark sweep support phase4
virtual void compact();
virtual void post_compact() { ShouldNotReachHere(); }
ReferenceProcessor* const ref_processor() { return _ref_processor; }
virtual void oop_iterate(ExtendedOopClosure* cl);
virtual void object_iterate(ObjectClosure* cl);
virtual void safe_object_iterate(ObjectClosure* cl);
virtual void younger_refs_iterate(OopsInGenClosure* cl, uint n_threads) = 0;
virtual void clear_remembered_set() { }
virtual void invalidate_remembered_set() { }
virtual HeapWord* block_start(const void* addr) const;
}
hotspot/src/share/vm/gc/serial/defNewGeneration.hpp
年轻代DefNewGeneration提供了如年龄表,标记栈,对象遍历操作等,并实现了基类的虚函数
class DefNewGeneration: public Generation {
AgeTable _age_table;
Stack<oop, mtGC> _promo_failure_scan_stack;
oop copy_to_survivor_space(oop old);
class FastKeepAliveClosure: public KeepAliveClosure {virtual void do_oop(oop* p);}
void compute_space_boundaries(uintx minimum_eden_size,bool clear_space,bool mangle_space);
size_t adjust_for_thread_increase(size_t new_size_candidate,size_t new_size_before,size_t alignment) const;
void swap_spaces(); //from,to空间交换
//......
}
hotspot/src/share/vm/gc/shared/cardGeneration.hpp
老年代TenuredGeneration继承自CardGeneration,提供了卡表,块偏移集合,并实现了基类的虚函数
class CardGeneration: public Generation {
// This is shared with other generations.
CardTableRS* _rs;
// This is local to this generation.
BlockOffsetSharedArray* _bts;
void space_iterate(SpaceClosure* blk, bool usedOnly = false);
//对年轻代的引用遍历
void younger_refs_iterate(OopsInGenClosure* blk, uint n_threads);
//......
}
HotSpot中的分代在每种收集器中都有自己的实现,CMS是Serial的并发版本,因此共享了部分分代逻辑。如CMS的年轻代ParNewGeneration 集成自 DefNewGeneration 。CMS老年代ConcurrentMarkSweepGeneration:继承自CardGeneration。而Parallel的分代则另起炉灶,Parallel的年轻代为PSYoungGen,老年代为PSOldGen,两者皆集成自CHeapObj。而G1更进一步,由于其算法的特殊性,将空间离散化为多个堆区间,并将gen,from,to,old的堆空间映射到这些离散的堆空间上,分代的概念在此被拆散了。
三.堆空间。
Serial收集器初始化时会创建收集堆GenCollectedHeap继承自CollectedHeap,CollectedHeap的子类还有G1CollectedHeap,ParallelScavengeHeap两者分别用于G1和Parallel收集器。
hotspot/src/share/vm/gc/shared/collectedHeap.hpp
CollectedHeap 提供了一组虚函数,由子类实现堆内存的分配,垃圾收集,管理
class CollectedHeap : public CHeapObj<mtInternal> {
MemRegion _reserved; //对应的内存区
BarrierSet* _barrier_set; //读写屏障
virtual HeapWord* allocate_new_tlab(size_t size); //分配TLAB
inline static HeapWord* allocate_from_tlab(KlassHandle klass, Thread* thread, size_t size);//通用分配
inline static HeapWord* common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS);
virtual bool is_in(const void* p) const = 0; //对象存在判断
inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);//对象分配
virtual HeapWord* mem_allocate(size_t size,bool* gc_overhead_limit_was_exceeded) = 0;
virtual void collect(GCCause::Cause cause) = 0; //收集
virtual void do_full_collection(bool clear_all_soft_refs) = 0;//全量收集
virtual void object_iterate(ObjectClosure* cl) = 0; //对象遍历
virtual HeapWord* block_start(const void* addr) const = 0;
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp
GenCollectedHeap代表年轻代,老年代的分代堆。提供了一组算法用于实现对象分配,对象遍历,垃圾收集,其中一些与CMS收集器共享复用。
class GenCollectedHeap : public CollectedHeap {
Generation* _young_gen;
Generation* _old_gen;
CardTableRS* _rem_set;
SubTasksDone* _process_strong_tasks; //并行收集有关
void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab,
bool run_verification, bool clear_soft_refs,
bool restore_marks_for_biased_locking);
void do_collection(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab,
GenerationType max_generation);
HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab);
WorkGang* workers() const { return _workers; } //并行收集有关
char* allocate(size_t alignment, ReservedSpace* heap_rs);
HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded);
void collect(GCCause::Cause cause);
void collect(GCCause::Cause cause, GenerationType max_generation);
void oop_iterate_no_header(OopClosure* cl);
void oop_iterate(ExtendedOopClosure* cl);
void object_iterate(ObjectClosure* cl);
void safe_object_iterate(ObjectClosure* cl);
Space* space_containing(const void* addr) const;
void generation_iterate(GenClosure* cl, bool old_to_young);
void process_roots(StrongRootsScope* scope,
ScanningOption so,
OopClosure* strong_roots,
OopClosure* weak_roots,
CLDClosure* strong_cld_closure,
CLDClosure* weak_cld_closure,
CodeBlobToOopClosure* code_roots);
void young_process_roots(StrongRootsScope* scope,
OopsInGenClosure* root_closure,
OopsInGenClosure* old_gen_closure,
CLDClosure* cld_closure);
void cms_process_roots(StrongRootsScope* scope,
bool young_gen_as_roots,
ScanningOption so,
bool only_strong_roots,
OopsInGenClosure* root_closure,
CLDClosure* cld_closure);
void gen_process_weak_roots(OopClosure* root_closure);
void prepare_for_compaction();
bool create_cms_collector();
}
如同上述分代一样,CMS收集器仍然共享了Serial收集器的分代堆GenCollectedHeap 。而Parallel和G1中则另起炉灶。Parallel的分代堆不再是GenCollectedHeap 而是ParallelScavengeHeap。G1则是G1CollectedHeap。
四.垃圾收集
1.触发GC
修改之前的Hello类如下循环创建大对象,触发GC
import java.util.ArrayList;
import java.util.List;
public class Hello{
public static void main(String[] args){
for (int i = 0; i < 5; i++) {
createBigObject(21);
System.gc()
}
}
private static void createBigObject(int n) {
List<byte[]> bytesList = new ArrayList<>();
for (int i = 0; i < n; i++) {
bytesList.add(new byte[1024 * 1024 * 10]);
}
if (bytesList.size() < 20) {
throw new RuntimeException("this is test");
}
}
}
hotspot/src/share/vm/runtime/vmThread.cpp
VMThread线程循环等待VM_Operation操作的到来,如上一篇当对象分配时空间不足时触发VM_GenCollectForAllocation类型的GC
void VMThread::loop() {
evaluate_operation(_cur_vm_operation);
}
hotspot/src/share/vm/runtime/vmThread.cpp
void VMThread::evaluate_operation(VM_Operation* op) {
op->evaluate();
}
hotspot/src/share/vm/runtime/vm_operations.cpp
void VM_Operation::evaluate() {
doit();
}
hotspot/src/share/vm/gc/shared/vmGCOperations.cpp
void VM_GenCollectForAllocation::doit() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
GCCauseSetter gccs(gch, _gc_cause);
_result = gch->satisfy_failed_allocation(_word_size, _tlab);
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
HeapWord* GenCollectedHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
return gen_policy()->satisfy_failed_allocation(size, is_tlab);
}
2.收集策略
hotspot/src/share/vm/gc/shared/collectorPolicy.cpp
由收集策略决定收集方式,分配流程如下:
- 如果存在GC锁,尝试扩展分配
- 如果最近一次回收没有失败,进行一次MinorGC
- 如果最近一次回收失败了,进行一次fullGC
- 2或3步GC后,再尝试分配
- 如果分配还是失败了,尝试扩展堆分配
- 如果还是没分配到则一定是堆内存溢出了,强制进行一次FullGC
- 强制FullGc后,再次试图分配
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) {
GenCollectedHeap *gch = GenCollectedHeap::heap();
GCCauseSetter x(gch, GCCause::_allocation_failure);
HeapWord* result = NULL;
if (GCLocker::is_active_and_needs_gc()) {
//尝试分配
if (!gch->is_maximal_no_gc()) {
result = expand_heap_and_allocate(size, is_tlab);
}
return result;
} else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) { //最近一次回收没有失败
//进行一次MinorGc
gch->do_collection(false, // full
false, // clear_all_soft_refs
size, // size
is_tlab, // is_tlab
GenCollectedHeap::OldGen); // max_generation
} else { //最近一次回收失败了
//进行一次fullGC
gch->do_collection(true, // full
false, // clear_all_soft_refs
size, // size
is_tlab, // is_tlab
GenCollectedHeap::OldGen); // max_generation
}
//尝试分配
result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
if (result != NULL) {
return result;
}
//尝试扩展堆分配
result = expand_heap_and_allocate(size, is_tlab);
if (result != NULL) {
return result;
}
//走到这里一定是内存溢出了,进行一次强制回收,软引用被回收
{
UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
gch->do_collection(true, // full
true, // clear_all_soft_refs
size, // size
is_tlab, // is_tlab
GenCollectedHeap::OldGen); // max_generation
}
//再次试图分配
result = gch->attempt_allocation(size, is_tlab, false /* first_only */);
if (result != NULL) {
return result;
}
//始终没分配到
return NULL;
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
do_collection是分代堆里封装的适用于各代的收集算法,对哪个分代收集取决于入参。主要流程如下:
- 如果do_young_collection成立,进行年轻代回收
- 如果最大分代为老年代且老年代应该回收(年轻代空间不足),进行一次老年代回收
- 重新调整堆大小
void GenCollectedHeap::do_collection(bool full,......) {
{
//进行一次年轻代GC
if (do_young_collection) {
collect_generation(_young_gen,
full,
size,
is_tlab,
run_verification && VerifyGCLevel <= 0,
do_clear_all_soft_refs,
false);
}
bool must_restore_marks_for_biased_locking = false;
//进行一次老年代收集
if (max_generation == OldGen && _old_gen->should_collect(full, size, is_tlab)) {
if (!complete) {
increment_total_full_collections();
}
if (do_young_collection) {
// 已经进行了一次yuongGC
GCIdMarkAndRestore gc_id_mark;
collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true);
} else {
// No young GC done. Use the same GC id as was set up earlier in this method.
collect_generation(_old_gen, full, size, is_tlab, run_verification && VerifyGCLevel <= 1, do_clear_all_soft_refs, true);
}
collected_old = true;
}
//重新调整个代堆大小
if (collected_old) {
_old_gen->compute_new_size();
}
_young_gen->compute_new_size();
//重新恢复偏向锁标记
if (must_restore_marks_for_biased_locking) {
BiasedLocking::restore_marks();
}
}
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
调用具体的分代去回收
void GenCollectedHeap::collect_generation(Generation* gen,...) {
gen->collect(full, clear_soft_refs, size, is_tlab);
}
3.年轻代回收
hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
年轻代回收,使用复制算法,将Eden空间的对象拷贝提升到to空间。各Closure分别对应各种对象遍历操作。主要流程:
- 遍历堆空间,线程栈等root引用链,将对象提升。
- 遍历所有promote到老年代的对象,恢复其对象头。
- Survivor的form和to空间交换。
void DefNewGeneration::collect(bool full,bool clear_all_soft_refs,size_t size,bool is_tlab) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
_old_gen = gch->old_gen();
// These can be shared for all code paths
IsAliveClosure is_alive(this);
ScanWeakRefClosure scan_weak_ref(this);
age_table()->clear();
to()->clear(SpaceDecorator::Mangle);
// The preserved marks should be empty at the start of the GC.
_preserved_marks_set.init(1);
gch->rem_set()->prepare_for_younger_refs_iterate(false);
// Not very pretty.
CollectorPolicy* cp = gch->collector_policy();
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier, gch->rem_set()->klass_rem_set());
CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure, &fsc_with_no_gc_barrier,false);
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
FastEvacuateFollowersClosure evacuate_followers(gch,&fsc_with_no_gc_barrier,&fsc_with_gc_barrier);
{
gch->young_process_roots(&srs,
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier,
&cld_scan_closure);
}
//遍历所有promote到老年代的对象,恢复其对象头,遍历其引用类型属性
evacuate_followers.do_void();
FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
ReferenceProcessor* rp = ref_processor();
rp->setup_policy(clear_all_soft_refs);
const ReferenceProcessorStats& stats =
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
NULL, _gc_timer);
if (!_promotion_failed) {
swap_spaces();
adjust_desired_tenuring_threshold();
} else {
swap_spaces(); // For uniformity wrt ParNewGeneration.
from()->set_next_compaction_space(to());
gch->set_incremental_collection_failed();
}
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
根对象遍历
void GenCollectedHeap::young_process_roots(StrongRootsScope* scope,
OopsInGenClosure* root_closure,
OopsInGenClosure* old_gen_closure,
CLDClosure* cld_closure) {
MarkingCodeBlobClosure mark_code_closure(root_closure, CodeBlobToOopClosure::FixRelocations);
process_roots(scope, SO_ScavengeCodeCache, root_closure, root_closure,
cld_closure, cld_closure, &mark_code_closure);
process_string_table_roots(scope, root_closure);
//......
}
hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp
根对象遍历,Universe::oops_do是对堆空间的遍历,其他如线程栈上根对象的引用遍历未列出
void GenCollectedHeap::process_roots(StrongRootsScope* scope,
ScanningOption so,
OopClosure* strong_roots,
OopClosure* weak_roots,
CLDClosure* strong_cld_closure,
CLDClosure* weak_cld_closure,
CodeBlobToOopClosure* code_roots) {
if (!_process_strong_tasks->is_task_claimed(GCH_PS_ClassLoaderDataGraph_oops_do)) {
ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure);
}
// Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway
CodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots;
bool is_par = scope->n_threads() > 1;
Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_code_p);
if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) {
Universe::oops_do(strong_roots);
}
//......
}
hotspot/src/share/vm/memory/universe.cpp
OopClosure对应FastScanClosure
void Universe::oops_do(OopClosure* f, bool do_all) {
f->do_oop((oop*) &_int_mirror);
//......
}
hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); }
hotspot/src/share/vm/gc/shared/genOopClosures.inline.hpp
这里进行对象提升等操作,具体copy_to_survivor_space
template <class T> inline void FastScanClosure::do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
// Should we copy the obj?
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if ((HeapWord*)obj < _boundary) {
assert(!_g->to()->is_in_reserved(obj), "Scanning field twice?");
oop new_obj = obj->is_forwarded() ? obj->forwardee()
: _g->copy_to_survivor_space(obj);
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
if (is_scanning_a_klass()) {
do_klass_barrier();
} else if (_gc_barrier) {
// Now call parent closure
do_barrier(p);
}
}
}
}
hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
如果是to空间不足则提升到老年代空间,老年代空间不足时将触发FullGC
oop DefNewGeneration::copy_to_survivor_space(oop old) {
size_t s = old->size();
oop obj = NULL;
// 尝试在to空间分配
if (old->age() < tenuring_threshold()) {
obj = (oop) to()->allocate_aligned(s);
}
//尝试在老年代分配
if (obj == NULL) {
obj = _old_gen->promote(old, s);
if (obj == NULL) {
handle_promotion_failure(old);
return old;
}
} else {
// Copy obj
Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)obj, s);
// 递增年龄
obj->incr_age();
age_table()->add(obj, s);
}
// Done, insert forward pointer to obj in this header
old->forward_to(obj);
return obj;
}
4.老年代回收
hotspot/src/share/vm/gc/serial/tenuredGeneration.cpp
老年代收集,使用标记压缩算法,特点是节省空间,防止内存碎片化
void TenuredGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
//进入收集器
GenMarkSweep::invoke_at_safepoint(ref_processor(), clear_all_soft_refs);
}
hotspot/src/share/vm/gc/serial/genMarkSweep.cpp
老年代收集流程如下:
- 使用标记栈标记存活对象
- 为标记栈中的对象计算一个新地址
- 将新地址更新到对象指针
- 移动对象到新地址处
void GenMarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, bool clear_all_softrefs) {
GenCollectedHeap* gch = GenCollectedHeap::heap();
set_ref_processor(rp);
rp->setup_policy(clear_all_softrefs);
CodeCache::gc_prologue();
// Increment the invocation count
_total_invocations++;
gch->save_used_regions();
//分配标记栈
allocate_stacks();
//标记存活的对象
mark_sweep_phase1(clear_all_softrefs);
//为存活的对象计算一个新的地址
mark_sweep_phase2();
//更新存活对象的对象指针
mark_sweep_phase3();
//移动存活对象到新的地址处
mark_sweep_phase4();
//销毁标记栈
deallocate_stacks();
//清除卡表信息
CardTableRS* rs = gch->rem_set();
Generation* old_gen = gch->old_gen();
//不存在引用,则清空。否则刷新
if (gch->young_gen()->used() == 0) {
// We've evacuated the young generation.
rs->clear_into_younger(old_gen);
} else {
rs->invalidate_or_clear(old_gen);
}
}
每一种收集算法都有自己的适用场景。如分代是基于大量对象存活周期较短的原则上产生的。标记压缩是基于空间利用率产生的。复制算法是基于回收效率因素产生的。而收集器是依据问题空间的大小来挑选合适的算法组建的。因此每种收集器都有其适用范围。虚拟机调优便是在问题空间和解空间找到最佳平衡点,这需要对虚拟机的足够了解也需要实践经验。