根据《JVM垃圾回收》我们对垃圾收集器有个初步的概念.
相关模块介绍
//VM_Operation
// VM_GC_Operation #是所有执行垃圾回收的VM_Operation的基类
// VM_CollectForAllocation #与其子类都是内存分配失败触发垃圾回收,然后尝试分配内存的操作
// VM_GenCollectForAllocation
//表示一类在JVM线程中执行的操作,类似java中的任务
//hotspot/src/share/vm/runtime/vm_operations.hpp
class VM_Operation: public CHeapObj<mtInternal> {
enum Mode {
_safepoint, //表示执行此操作需要加锁+安全点
_no_safepoint, //表示执行此操作需要加锁
_concurrent, //无需要任务条件
_async_safepoint //表示执行此操作需要安全点
};
//具体执行VM_Operation的方法,通过evaluate方法调用,子类不能改写evaluate方法的实现
doit:
//用于执行准备工作,当Java线程调用VMThread::execute((VM_Operation*)执行某个VM_Operation时会先执行doit_prologue如果该方法返回true才会执行evaluate方法,否则被取消不执行。
doit_prologue
//用于执行某些依赖于VM_Operation执行结果的动作,当VM_Operation执行完成,Java线程会调用doit_epilogue方法一次。
doit_epilogue
}
//表示一个特殊的专门用来执行比较耗时的VM_Operation的原生线程
//hotspot/src/share/vm/runtime/vMThread.hpp
class VMThread {
//当前执行的VM operation
static VM_Operation* _cur_vm_operation;
// 缓存待执行的VM operation 队列
static VMOperationQueue* _vm_queue;
void VMThread::create() {
//创建VMThread线程,及VMOperationQueue队列
}
void VMThread::execute(VM_Operation* op) {
//用于执行某个VM_Operation,execute方法会先执行doit_prologue,该方法执行成功后将该操作放入一个等待队列中,然后等待VMThread执行该操作完成,最后再执行doit_epilogue
}
void VMThread::run() {
//其中loop方法执行的核心业务逻辑了,该方法不断从待执行的VM Operation队列_vm_queue中获取待执行的VM_Operation实例,然后调用其evaluate方法
}
}
//描述分代参数的一个类
//hotspot/src/share/vm/memory/generationSpec.hpp
class GenerationSpec : public CHeapObj<mtGC> {
Generation::Name _name;//分代名
size_t _init_size;//初始大步
size_t _max_size;//最大大小
// 返回这个分代所需要的 remembered set 空间.
virtual int n_covered_regions() const { return 1; }
//创建分带代
Generation* GenerationSpec::init(ReservedSpace rs, int level,
GenRemSet* remset) {
switch (name()) {
case Generation::DefNew:
return new DefNewGeneration(rs, init_size(), level);
case Generation::MarkSweepCompact:
return new TenuredGeneration(rs, init_size(), level, remset);
case Generation::ParNew:
return new ParNewGeneration(rs, init_size(), level);
case Generation::ASParNew:
return new ASParNewGeneration(rs,init_size(),init_size() ,level);
case Generation::ConcurrentMarkSweep: {
assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set");
CardTableRS* ctrs = remset->as_CardTableRS();
if (ctrs == NULL) {
vm_exit_during_initialization("Rem set incompatibility.");
}
// Otherwise
// The constructor creates the CMSCollector if needed,
// else registers with an existing CMSCollector
ConcurrentMarkSweepGeneration* g = NULL;
g = new ConcurrentMarkSweepGeneration(rs,
init_size(), level, ctrs, UseCMSAdaptiveFreeLists,
(FreeBlockDictionary<FreeChunk>::DictionaryChoice)CMSDictionaryChoice);
g->initialize_performance_counters();
return g;
}
case Generation::ASConcurrentMarkSweep: {
//...
}
default:
guarantee(false, "unrecognized GenerationName");
return NULL;
}
}
}
//用来记录不同分代年龄的对象的大小,然后据此动态调整tenuring_threshold
//hotspot/src/share/vm/gc_implementation/shared/ageTable.hpp
class ageTable {
enum { table_size = markOopDesc::max_age + 1 };
//sizes就是保存不同分代年龄的对象的大小的数组
size_t sizes[table_size];
//所对象存进行
//如果想取1岁对象占分代的大小,就直接sizes[1]
void add(oop p, size_t oop_size) {
add(p->age(), oop_size);
}
void add(uint age, size_t oop_size) {
sizes[age] += oop_size;
}
//传一个的survivor_capacity值,根据ageTable的数据,把对象重新画区
uint ageTable::compute_tenuring_threshold(size_t survivor_capacity)
}
//Space及其子类是Generation中用于内存分配管理的底层实现
//hotspot/src/share/vm/memory/space.hpp
class Space: public CHeapObj<mtGC> {
//内存区域的起始地址
HeapWord* _bottom;
//内存区域的终止地址
HeapWord* _end;
// 用来遍历Space内的MemRegion
MemRegionClosure* _preconsumptionDirtyCardClosure;
}
//增加了压缩操作的支持,即在垃圾回收后通过复制移动Java对象的位置减少Space内部的内存空洞和碎片问题,提升内存利用率
//hotspot/src/share/vm/memory/space.hpp
class CompactibleSpace: public Space {
}
//表示一个空闲内存空间是地址连续的Space,从而支持快速的内存分配和压缩
//hotspot/src/share/vm/memory/space.hpp
class ContiguousSpace: public CompactibleSpace {
//bottom到top之间的内存都是已经被分配出去的内存
HeapWord* _top;
//从bottom到_concurrent_iteration_safe_limit之间的对象都被认为是已经初始化完成的对象,对于object_iterate_careful方法可以安全遍历的,该属性在初始化时通常设置为bottom,在compact结束后设置为compact_top。
HeapWord* _concurrent_iteration_safe_limit;
//负责对Space执行mangle的辅助类
GenSpaceMangler* _mangler;
}
//用来表示Eden区
class EdenSpace : public ContiguousSpace {
//关联的年轻代DefNewGeneration实例
DefNewGeneration* _gen;
//分配内存的一个软限制, 当达到了这个限制后,慢速分配的代码可以执行其他的逻辑,然后调整_soft_end到一个新的限制或者end()
HeapWord* _soft_end;
}
// CollectedHeap
// SharedHeap 分层的堆基类
// GenCollectedHeap 普通分带法
// G1CollectedHeap G1分带法
// ParallelScavengeHeap ps分带及策略
//一个抽象类,表示一个Java堆,定义了各种垃圾回收算法必须实现的公共接口,这些接口就是上层类用来分配Java对象,分配TLAB,获取Java堆使用情况等的统一API
//hotspot/src/share/vm/gc_interface/collectedHeap.hpp
class CollectedHeap : public CHeapObj<mtInternal> {
//填充数组的最大值
static size_t _filler_array_max_size;
//用来打印GC日志
GCHeapLog* _gc_heap_log;
//开启C2编译时使用,支持ReduceInitialCardMarks
bool _defer_initial_card_mark;
//Java堆对应的一段连续内存空间
MemRegion _reserved;
//卡表(CardTable)的基类
//BarrierSet的功能类似于一个拦截器,在读写动作实际作用于内存前执行某些前置或者后置动作
BarrierSet* _barrier_set;
//是否正在执行GC
bool _is_gc_active;
//并行执行GC任务的线程数
uint _n_par_threads;
//从JVM启动至今的GC次数
unsigned int _total_collections;
//从JVM启动至今的Full GC次数
unsigned int _total_full_collections;
//当前GC被触发的原因,Cause是GCCause定义的枚举
GCCause::Cause _gc_cause;
//上一次GC被触发的原因
GCCause::Cause _gc_lastcause;
//开启UsePerfData时用来保存_gc_cause
PerfStringVariable* _perf_gc_cause;
//开启UsePerfData时用来保存_gc_lastcause
PerfStringVariable* _perf_gc_lastcause;
}
//hotspot/src/share/vm/memory/sharedHeap.hpp
class SharedHeap : public CollectedHeap {
//静态SharedHeap实例,单例
static SharedHeap* _sh;
// the Gen Remembered Set,卡表实现
GenRemSet* _rem_set;
//垃圾回收策略
CollectorPolicy *_collector_policy;
//遍历Java线程包含的oop使用的
int _strong_roots_parity;
//执行并行GC(parallel GC)的线程池
FlexibleWorkGang* _workers;
//SharedHeap构造
SharedHeap::SharedHeap(CollectorPolicy* policy_) :
CollectedHeap(),
_collector_policy(policy_),
_rem_set(NULL),
_strong_roots_parity(0),
_workers(NULL)
{
//初始化静态属性_sh
_sh = this; // ch is static, should be set only once.
if ((UseParNewGC ||
(UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled ||
CMSParallelRemarkEnabled)) ||
UseG1GC) &&
ParallelGCThreads > 0) {
//初始化执行并行GC的线程池
_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
if (_workers == NULL) {
vm_exit_during_initialization("Failed necessary allocation.");
} else {
_workers->initialize_workers();
}
}
}
}
//heap具体的分带实现
//hotspot/src/share/vm/memory/genCollectedHeap.hpp
class GenCollectedHeap : public SharedHeap {
//静态GenCollectedHeap实例,单例
static GenCollectedHeap* _gch;
//包含的Generation的个数,通常是2(老年代,年轻带)
int _n_gens;
//Generation数组,分代的具体指针
Generation* _gens[max_gens];
//GenerationSpec主要用来存储各分带的创建数据
GenerationSpec** _gen_specs;
//垃圾回收策略
GenCollectorPolicy* _gen_policy;
//执行promote是否会失败
bool _incremental_collection_failed;
//已经执行万恒的Full GC的次数
unsigned int _full_collections_completed;
//用于控制根节点遍历任务的并行执行
SubTasksDone* _process_strong_tasks;
//GenCollectedHeap构造
GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :
SharedHeap(policy),
_gen_policy(policy),
_process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)),
_full_collections_completed(0)
{
assert(policy != NULL, "Sanity check");
}
jint GenCollectedHeap::initialize() {
CollectedHeap::pre_initialize();
int i;
//_n_gens表示有多少代,通常是2代,年轻代和老年代
_n_gens = gen_policy()->number_of_generations();
guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize");
size_t gen_alignment = Generation::GenGrain;
//拿出堆模型数据
_gen_specs = gen_policy()->generations();
for (i = 0; i < _n_gens; i++) {
//将内存的初始值和最大值按照内存分配粒度对齐
_gen_specs[i]->align(gen_alignment);
}
char* heap_address;
size_t total_reserved = 0;
int n_covered_regions = 0;
ReservedSpace heap_rs;
size_t heap_alignment = collector_policy()->heap_alignment();
//根据各GenerationSpec的最大大小计算总的需要保留的内存空间,然后申请指定大小的连续内存空间
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs);
if (!heap_rs.is_reserved()) {
//申请失败
vm_shutdown_during_initialization(
"Could not reserve enough space for object heap");
return JNI_ENOMEM;
}
//设置_reserved相关属性
_reserved = MemRegion((HeapWord*)heap_rs.base(),
(HeapWord*)(heap_rs.base() + heap_rs.size()));
_reserved.set_word_size(0);
_reserved.set_start((HeapWord*)heap_rs.base());
size_t actual_heap_size = heap_rs.size();
_reserved.set_end((HeapWord*)(heap_rs.base() + actual_heap_size));
//collector_policy()和gen_policy()表示相同变量
//根据各区域名需要的_rem_set区域,初始化GenRemSet
_rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions);
set_barrier_set(rem_set()->bs());
_gch = this;
//初始化各Generation
for (i = 0; i < _n_gens; i++) {
//提取出max_size的内存
ReservedSpace this_rs = heap_rs.first_part(_gen_specs[i]->max_size(), false, false);
//使用提取出的,内存和卡表引出,创建初始化分代
_gens[i] = _gen_specs[i]->init(this_rs, i, rem_set());
//将下次内存指针向下移max_size
heap_rs = heap_rs.last_part(_gen_specs[i]->max_size());
}
//将_incremental_collection_failed置为false
clear_incremental_collection_failed();
#if INCLUDE_ALL_GCS
if (collector_policy()->is_concurrent_mark_sweep_policy()) {
//如果是CMS则创建CMSCollector
bool success = create_cms_collector();
if (!success) return JNI_ENOMEM;
}
#endif // INCLUDE_ALL_GCS
return JNI_OK;
}
char* GenCollectedHeap::allocate(size_t alignment,
size_t* _total_reserved,
int* _n_covered_regions,
ReservedSpace* heap_rs){
const char overflow_msg[] = "The size of the object heap + VM data exceeds "
"the maximum representable size";
// Now figure out the total size.
size_t total_reserved = 0;
int n_covered_regions = 0;
const size_t pageSize = UseLargePages ?
os::large_page_size() : os::vm_page_size();
assert(alignment % pageSize == 0, "Must be");
//遍历所有的_gen_specs,累加各GenerationSpec的max_size和n_covered_regions
for (int i = 0; i < _n_gens; i++) {
total_reserved += _gen_specs[i]->max_size();
if (total_reserved < _gen_specs[i]->max_size()) {
vm_exit_during_initialization(overflow_msg);
}
n_covered_regions += _gen_specs[i]->n_covered_regions();
}
//校验累加后的total_reserved已经是内存对齐的
assert(total_reserved % alignment == 0,
err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment="
SIZE_FORMAT, total_reserved, alignment));
//加2是为卡表保留的
n_covered_regions += 2;
//赋值
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
//申请指定大小的连续内存空间
*heap_rs = Universe::reserve_heap(total_reserved, alignment);
//返回基地址
return heap_rs->base();
}
//执行垃圾回收的核心方法,其底层核心就是各Genaration的collect方法
void GenCollectedHeap::do_collection(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab,
int max_level) {
bool prepared_for_verification = false;
ResourceMark rm;
//校验处于安全点上
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
//校验调用线程是VMThread 或者CMS Thread
assert(my_thread->is_VM_thread() ||
my_thread->is_ConcurrentGC_thread(),
"incorrect thread type capability");
//校验获取了Heap_lock锁
assert(Heap_lock->is_locked(),
"the requesting thread should have the Heap_lock");
guarantee(!is_gc_active(), "collection is not reentrant");
assert(max_level < n_gens(), "sanity check");
//检查是否有线程处于JNI关键区,check_active_before_gc返回true表示有,则终止当前GC,等待线程退出
//最后一个退出的线程会负责执行GC
if (GC_locker::check_active_before_gc()) {
return;
}
//是否需要清除软引用
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
collector_policy()->should_clear_all_soft_refs();
//ClearedAllSoftRefs通过析构函数设置CollectorPolicy的_all_soft_refs_clear属性
ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
//获取元空间已使用内存
const size_t metadata_prev_used = MetaspaceAux::used_bytes();
//打印GC的堆内存使用情况
print_heap_before_gc();
{
//临时设置_is_gc_active为true,表示GC开始了
FlagSetting fl(_is_gc_active, true);
bool complete = full && (max_level == (n_gens()-1));
const char* gc_cause_prefix = complete ? "Full GC" : "GC";
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL, GCId::peek());
//遍历各Generation执行GC准备工作
gc_prologue(complete);
//增加GC次数
increment_total_collections(complete);
//统计总的内存使用量
size_t gch_prev_used = used();
int starting_level = 0;
if (full) {
//如果老年代设置了full Gc要先收集年轻代的话
//full_collects_younger_generations = false
//否则为true,starting_level=1
for (int i = max_level; i >= 0; i--) {
if (_gens[i]->full_collects_younger_generations()) {
starting_level = i;
break;
}
}
}
bool must_restore_marks_for_biased_locking = false;
int max_level_collected = starting_level;
for (int i = starting_level; i <= max_level; i++) {
if (_gens[i]->should_collect(full, size, is_tlab)) {
//如果需要垃圾回收
if (i == n_gens() - 1) { // a major collection is to happen
//如果是老年代
if (!complete) {
//increment_total_collections方法只有在complete为true时才会增加_total_full_collections计数
//此处complete为false,但还是老年代的GC,所以增加计数
increment_total_full_collections();
}
//根据参数配置dump
pre_full_gc_dump(NULL); // do any pre full gc dumps
}
GCTraceTime t1(_gens[i]->short_name(), PrintGCDetails, false, NULL, GCId::peek());
TraceCollectorStats tcs(_gens[i]->counters());
TraceMemoryManagerStats tmms(_gens[i]->kind(),gc_cause());
size_t prev_used = _gens[i]->used();
//增加计数
_gens[i]->stat_record()->invocations++;
_gens[i]->stat_record()->accumulated_time.start();
//记录各Generation的Space的top指针,生产版本为空实现
record_gen_tops_before_GC();
if (PrintGC && Verbose) {
gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
i,
_gens[i]->stat_record()->invocations,
size*HeapWordSize);
}
if (VerifyBeforeGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
if (!prepared_for_verification) {
prepare_for_verify();
prepared_for_verification = true;
}
Universe::verify(" VerifyBeforeGC:");
}
COMPILER2_PRESENT(DerivedPointerTable::clear());
if (!must_restore_marks_for_biased_locking &&
//DefNewGeneration返回false,ConcurrentMarkSweepGeneration采用父类默认实现返回true
_gens[i]->performs_in_place_marking()) {
must_restore_marks_for_biased_locking = true;
//将各线程的持有偏向锁的oop的对象头保存起来
BiasedLocking::preserve_marks();
}
// Do collection work
{
HandleMark hm; // Discard invalid handles created during gc
save_marks(); // save marks for all gens
ReferenceProcessor* rp = _gens[i]->ref_processor();
if (rp->discovery_is_atomic()) {
rp->enable_discovery(true /*verify_disabled*/, true /*verify_no_refs*/);
rp->setup_policy(do_clear_all_soft_refs);
} else {
//collect方法会调用enable_discovery方法
}
//执行垃圾回收
_gens[i]->collect(full, do_clear_all_soft_refs, size, is_tlab);
if (!rp->enqueuing_is_done()) {
//enqueuing_is_done为false
//将处理后剩余的References实例加入到pending-list中
rp->enqueue_discovered_references();
} else {
//enqueuing_is_done为true,已经加入到pending-list中了,将其恢复成默认值
rp->set_enqueuing_is_done(false);
}
rp->verify_no_references_recorded();
}
max_level_collected = i;
// Determine if allocation request was met.
if (size > 0) {
if (!is_tlab || _gens[i]->supports_tlab_allocation()) {
if (size*HeapWordSize <= _gens[i]->unsafe_max_alloc_nogc()) {
size = 0;
}
}
}
COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
_gens[i]->stat_record()->accumulated_time.stop();
//更新各Generation的GC统计信息
update_gc_stats(i, full);
if (VerifyAfterGC && i >= VerifyGCLevel &&
total_collections() >= VerifyGCStartAt) {
HandleMark hm; // Discard invalid handles created during verification
Universe::verify(" VerifyAfterGC:");
}
if (PrintGCDetails) {
gclog_or_tty->print(":");
_gens[i]->print_heap_change(prev_used);
}
}
}//for循环结束
//是否Full GC
complete = complete || (max_level_collected == n_gens() - 1);
if (complete) { // We did a "major" collection
//根据配置dump
post_full_gc_dump(NULL); // do any post full gc dumps
}
if (PrintGCDetails) {
print_heap_change(gch_prev_used);
if (complete) {
MetaspaceAux::print_metaspace_change(metadata_prev_used);
}
}
for (int j = max_level_collected; j >= 0; j -= 1) {
//调整各Generation的容量
_gens[j]->compute_new_size();
}
if (complete) {
//删掉被卸载的ClassLoader实例及其相关元数据
ClassLoaderDataGraph::purge();
MetaspaceAux::verify_metrics();
//重置元空间大小
MetaspaceGC::compute_new_size();
update_full_collections_completed();
}
//跟踪GC后的内存使用
MemoryService::track_memory_usage();
gc_epilogue(complete);
if (must_restore_marks_for_biased_locking) {
BiasedLocking::restore_marks();
}
}
AdaptiveSizePolicy* sp = gen_policy()->size_policy();
AdaptiveSizePolicyOutput(sp, total_collections());
print_heap_after_gc();
}
//DefNewGeneration采用父类Generation的默认实现,返回false
//ConcurrentMarkSweepGeneration的实现如下
//UseCMSCompactAtFullCollection默认为true,表示FullGC时所使用Mark-Sweep-Compact算法
//CollectGen0First默认为false,表示是否在FullGC前收集年轻代
virtual bool full_collects_younger_generations() const {
return UseCMSCompactAtFullCollection && !CollectGen0First;
}
}
// Generation
// CardGeneration
// ConcurrentMarkSweep #cms
// ASConcurrentMarkSweep # 自适应cms
// OneContigSpaceCardGeneration
// TenuredGeneration
// DefNewGeneration
// ParNewGeneration
// ASParNewGeneration
//CMS算法使用的表示年轻代的DefNewGeneration和表示支持自适应调整堆内存大小的老年代的ASConcurrentMarkSweepGeneration类
//表示分代内存中的一个“代”对应的内存区域,是各种分代内存实现的抽象类
//hotspot/src/share/vm/memory/generation.hpp
class Generation: public CHeapObj<mtGC> {
//记录上一次GC的发生时间
jlong _time_of_last_gc;
//在GC过程中的某个特殊时点使用的,用于记录某个值
MemRegion _prev_used_region;
//为当前Generation保留的一段连续的内存地址空间,注意不能跟其他的Generation的地址空间有交叉
MemRegion _reserved;
// Memory area reserved for generation
VirtualSpace _virtual_space;
//当前Generation在类继承关系中的级别
int _level;
//用于处理Reference实例的处理器
ReferenceProcessor* _ref_processor;
//用于GC性能跟踪
CollectorCounters* _gc_counters;
//收集GC的统计数据
GCStats* _gc_stats;
//Generation定义了一个枚举Name来描述各子类,其定义如下:
enum Name {
ASParNew,
ASConcurrentMarkSweep,
DefNew,
ParNew,
MarkSweepCompact,(对应继承类TenuredGeneration)
ConcurrentMarkSweep,
Other
};
//默认种类返回
virtual Generation::Name kind() { return Generation::Other;}
//是否要收集
//如果full为true,强制收集
//否则判断空间是否充足
virtual bool should_collect(bool full,
size_t word_size,
bool is_tlab) {
return (full || should_allocate(word_size, is_tlab));
}
}
//表示一个使用卡表来标记对象修改
//hotspot/src/share/vm/memory/generation.hpp
class CardGeneration: public Generation {
//与其他Generation实例共享的卡表实现实例(指向SharedHeap中的)
GenRemSet* _rs;
//当前Generation独享的BlockOffsetArray实现
//记录内存块的起始位置
BlockOffsetSharedArray* _bts;
//老年代内存缩容的百分比,第一次是0,第二次是10,第三次是40,第四次是100,中间有一次扩容了则被重置为0,重新开始累加,避免频繁的缩容与扩容。
size_t _shrink_factor;
//老年代内存扩展或者缩容时的最低内存值
size_t _min_heap_delta_bytes;
//GC开始时的内存容量
size_t _capacity_at_prologue;
//GC开始时的内存使用量
size_t _used_at_prologue;
}
//表示CMS的老年代
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp
class ConcurrentMarkSweepGeneration: public CardGeneration {
//封装了老年代垃圾回收的相关属性和实现逻辑
static CMSCollector* _collector;
//老年代对应的Space实现
CompactibleFreeListSpace* _cmsSpace;
//直接从老年代分配而非promote时间接分配的内存的大小,是一个累加值,CMSStats使用的
size_t _direct_allocated_words;
//是否增量收集失败
bool _incremental_collection_failed;
//实际是一个CMSParGCThreadState指针数组,元素个数就是ParallelGCThreads,即并行GC的线程数,CMSParGCThreadState是执行老年代promote时使用的
CMSParGCThreadState** _par_gc_thread_states;
//老年代扩展的原因,shouldConcurrentCollect()方法据此判断是否应该GC
CMSExpansionCause::Cause _expansion_cause;
//是否完成压缩
bool _did_compact;
//触发老年代GC的内存占用百分比,是一个两位的小数
double _initiating_occupancy;
//UseCMSCompactAtFullCollection默认为true,表示FullGC时所使用Mark-Sweep-Compact算法
//CollectGen0First默认为false,表示是否在FullGC前收集年轻代
virtual bool full_collects_younger_generations() const {
return UseCMSCompactAtFullCollection && !CollectGen0First;
}
}
//表示年轻代,包括(den, from- and to-space.)
//hotspot/src/share/vm/memory/defNewGeneration.hpp
class DefNewGeneration: public Generation {
//对老年代的引用,初始化时为null,第一次GC时会赋值
Generation* _next_gen;
//将对象拷贝到老年代的分代年龄阈值,大于该值拷贝到老年代,否则拷贝到to区,该值在初始化时赋值成参数MaxTenuringThreshold,默认是15;每次GC结束后都会通过ageTable调整。
uint _tenuring_threshold;
//记录不同分代年龄的对象的总大小
ageTable _age_table;
//表示年轻代中允许分配的对象的最大字宽数,默认是0,即无限制
size_t _pretenure_size_threshold_words;
//真实地址大内存在ReservedSpace已经外面
//用EdenSpace与ContiguousSpace等类,标识已计算出给年代代的东西
//barrier_set也得新高监听区域
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
int level,
const char* policy)
: Generation(rs, initial_size, level),
_promo_failure_drain_in_progress(false),
_should_allocate_from_space(false)
{
MemRegion cmr((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
//重置bs对应的内存区域
Universe::heap()->barrier_set()->resize_covered_region(cmr);
//has_soft_ended_eden方法的返回值取决于属性CMSIncrementalMode,默认为false
//初始化三个内存区域
if (GenCollectedHeap::heap()->collector_policy()->has_soft_ended_eden()) {
_eden_space = new ConcEdenSpace(this);
} else {
_eden_space = new EdenSpace(this);
}
_from_space = new ContiguousSpace();
_to_space = new ContiguousSpace();
if (_eden_space == NULL || _from_space == NULL || _to_space == NULL)
vm_exit_during_initialization("Could not allocate a new gen space");
//计算survivor区和eden区的最大空间,即年轻代最大内存时survivor区和eden区的内存空间
uintx alignment = GenCollectedHeap::heap()->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);
//...
}
HeapWord* DefNewGeneration::allocate(size_t word_size,
bool is_tlab) {
//正常情况下只有慢速分配对象时才会进入此方法,此时在GenCollectHeap层已经获取了锁
//par_allocate不要求调用方获取全局锁,底层使用cmpxchg原子指令,更快
HeapWord* result = eden()->par_allocate(word_size);
if (result != NULL) {
//如果分配成功
//CMSEdenChunksRecordAlways表示是否记录eden区分配的内存块,默认为true
if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
_next_gen->sample_eden_chunk();
}
return result;
}
do {
HeapWord* old_limit = eden()->soft_end();
if (old_limit < eden()->end()) {
//通知老年代,年轻代已经达到了分配限制soft_end,老年代会返回一个新的限制
//非iCMS模式下,该方法就是返回NULL,就end和soft_end一直
HeapWord* new_limit =
next_gen()->allocation_limit_reached(eden(), eden()->top(), word_size);
if (new_limit != NULL) {
//原子的修改eden区的soft_end属性
Atomic::cmpxchg_ptr(new_limit, eden()->soft_end_addr(), old_limit);
} else {
assert(eden()->soft_end() == eden()->end(),
"invalid state after allocation_limit_reached returned null");
}
} else {
//soft_end跟end一致了,必须扩容才能继续分配,终止循环
assert(old_limit == eden()->end(), "sanity check");
break;
}
//再次尝试分配,直到分配成功或者soft_end跟end一致
result = eden()->par_allocate(word_size);
} while (result == NULL);
if (result == NULL) {
//从from区域分配内存
result = allocate_from_space(word_size);
} else if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
//while循环重试分配成功
_next_gen->sample_eden_chunk();
}
return result;
}
//此方法的四个参数只有clear_all_soft_refs是有用的参数,如果为true表示会清除所有的软引用
//如果是false则按照默认逻辑处理
void DefNewGeneration::collect(bool full,
bool clear_all_soft_refs,
size_t size,
bool is_tlab) {
assert(full || size > 0, "otherwise we don't want to collect");
GenCollectedHeap* gch = GenCollectedHeap::heap();
//记录GC的开始时间和原因
//...
//老年代
_next_gen = gch->next_gen(this);
//判断老年代是否有足够的空间保存年轻代复制过去的对象
if (!collection_attempt_is_safe()) {
//通知GCH老年代空间不足
gch->set_incremental_collection_failed(); // Slight lie: we did not even attempt one
//老年代空间不足,终止年轻代的GC
return;
}
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
//将_promotion_failed属性置为false,记录promote失败信息的PromotionFailedInfo重置成初始状态
init_assuming_no_promotion_failure();
GCTraceTime t1(GCCauseString("GC", gch->gc_cause()), PrintGC && !PrintGCDetails, true, NULL, gc_tracer.gc_id());
// Capture heap used before collection (for printing).
size_t gch_prev_used = gch->used();
//设置GC Tracer
gch->trace_heap_before_gc(&gc_tracer);
SpecializationStats::clear();
//初始化两个遍历器
IsAliveClosure is_alive(this);
ScanWeakRefClosure scan_weak_ref(this);
//重置ageTable
age_table()->clear();
//重置to区
to()->clear(SpaceDecorator::Mangle);
//重置cur_youngergen_card_val,并行遍历脏的卡表项时使用
gch->rem_set()->prepare_for_younger_refs_iterate(false);
assert(gch->no_allocs_since_save_marks(0),
"save marks have not been newly set.");
CollectorPolicy* cp = gch->collector_policy();
//FastScanClosure用来遍历年轻代中的存活对象oop,第二个参数为true,表示会将oop对应的卡表项置为youngergen_card
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
//KlassScanClosure用来遍历在上一次GC到当前GC之间创建的新的Klass对应的Class实例
KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier,
gch->rem_set()->klass_rem_set());
//CLDToKlassAndOopClosure用来遍历一个ClassLoader加载的所有类对应的Class实例和依赖等
CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
&fsc_with_no_gc_barrier,
false);
//设置promote失败时的遍历器
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
//FastEvacuateFollowersClosure主要用来遍历被promote到老年代的对象,恢复其对象头并遍历其引用类型属性
FastEvacuateFollowersClosure evacuate_followers(gch, _level, this,
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier);
assert(gch->no_allocs_since_save_marks(0),
"save marks have not been newly set.");
//执行根节点遍历以及老年代新应用的oop遍历
gch->gen_process_roots(_level, //level就是0
true, //因为level是0,所以此参数实际无意义
true, // StrongRootsScope的active入参为true
GenCollectedHeap::SO_ScavengeCodeCache, //只遍历nmethod中的oop
GenCollectedHeap::StrongAndWeakRoots,//StrongAndWeakRoots是静态常量,值为false,表示会遍历weak root,如StringTable中的String对象
&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);
//处理do_void方法遍历引用类型属性过程中找到的Reference实例,如果该实例的referent对象是存活的,则从待处理列表中移除,否则将referent属性置为null
const ReferenceProcessorStats& stats =
rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
NULL, _gc_timer, gc_tracer.gc_id());
gc_tracer.report_gc_reference_stats(stats);
if (!_promotion_failed) {
//promote没有失败的
//重置清空eden区和from区
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
if (ZapUnusedHeapArea) {
to()->mangle_unused_area();
}
//交换from区和to区
swap_spaces();
//交换后,原来的from区变成to区,必须是空的
assert(to()->is_empty(), "to space should be empty now");
//调整tenuring_threshold
adjust_desired_tenuring_threshold();
AdaptiveSizePolicy* size_policy = gch->gen_policy()->size_policy();
//重置gc_overhead_limit_count
size_policy->reset_gc_overhead_limit_count();
if (PrintGC && !PrintGCDetails) {
gch->print_heap_change(gch_prev_used);
}
assert(!gch->incremental_collection_failed(), "Should be clear");
} else {
//如果存在promote失败的情形
assert(_promo_failure_scan_stack.is_empty(), "post condition");
//drain_promo_failure_scan_stack方法会负责处理掉里面保存的oop,遍历其所引用的其他oop,找到的oop的处理逻辑就是fsc_with_no_gc_barrier
//释放_promo_failure_scan_stack的内存,
_promo_failure_scan_stack.clear(true); // Clear cached segments.
//移除from区和eden区包含的对象的froward指针
remove_forwarding_pointers();
if (PrintGCDetails) {
gclog_or_tty->print(" (promotion failed) ");
}
//交换from区和to区,注意此时eden区和from区因为promote失败所以不是空的,还有存活对象
swap_spaces(); // For uniformity wrt ParNewGeneration.
//将to区作为from区的next_compaction_space,正常为NULL
from()->set_next_compaction_space(to());
//将incremental_collection_failed置为true
gch->set_incremental_collection_failed();
//通知老年代promote失败,CMS老年代实际不做处理
_next_gen->promotion_failure_occurred();
gc_tracer.report_promotion_failed(_promotion_failed_info);
}
//设置并行遍历时的边界
from()->set_concurrent_iteration_safe_limit(from()->top());
to()->set_concurrent_iteration_safe_limit(to()->top());
SpecializationStats::print();
//更新GC完成时间
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
gch->trace_heap_after_gc(&gc_tracer);
gc_tracer.report_tenuring_threshold(tenuring_threshold());
_gc_timer->register_gc_end();
//更新GC日志
gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
}
oop DefNewGeneration::copy_to_survivor_space(oop old) {
assert(is_in_reserved(old) && !old->is_forwarded(),
"shouldn't be scavenging this oop");
size_t s = old->size();
oop obj = NULL;
// Try allocating obj in to-space (unless too old)
if (old->age() < tenuring_threshold()) {
//如果对象的年龄低于tenuring_threshold,则该在to区申请一块同样大小的内存
obj = (oop) to()->allocate_aligned(s);
}
// Otherwise try allocating obj tenured
if (obj == NULL) {
//如果如果对象的年龄大于tenuring_threshold或者to区申请内存失败
//则尝试将该对象复制到老年代
obj = _next_gen->promote(old, s);
if (obj == NULL) {
//复制失败
handle_promotion_failure(old);
return old;
}
} else {
//to区中申请内存成功
const intx interval = PrefetchCopyIntervalInBytes;
Prefetch::write(obj, interval);
//对象复制
Copy::aligned_disjoint_words((HeapWord*)old, (HeapWord*)obj, s);
//增加年龄,并修改age_table,增加对应年龄的总对象大小
//注意此处是增加复制对象而非原来对象的分代年龄
obj->incr_age();
age_table()->add(obj, s);
}
//将对象头指针指向新地址
old->forward_to(obj);
return obj;
}
}
//定义垃圾回收器使用的全局属性,并初始化分代内存及其他共享资源
// CollectorPolicy
// G1CollectorPolicy
// G1CollectorPolicyExt
// GenCollectorPolicy
// TwoGenerationCollectorPolicy
// ConcurrentMarkSweepPolicy
// ASConcurrentMarkSweepPolicy
// GenerationSizer
// MarkSweepPolicy
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class CollectorPolicy : public CHeapObj<mtGC> {
//跟踪分代内存的性能的计数器
GCPolicyCounters* _gc_policy_counters;
//初始堆内存
size_t _initial_heap_byte_size;
//最大堆内存
size_t _max_heap_byte_size;
//最小堆内存
size_t _min_heap_byte_size;
//space分配粒度
size_t _space_alignment;
//heap分配粒度,_heap_alignment必须大于_space_alignment,且是_space_alignment的整数倍
size_t _heap_alignment;
//是否通过命令行参数设置了最大堆内存
bool _max_heap_size_cmdline;
//用来自适应调整堆内存大小的策略实现
AdaptiveSizePolicy* _size_policy;
//是否需要清除所有的软引用,当软引用清除结束,垃圾回收器会将其置为false
bool _should_clear_all_soft_refs;
//当GC刚清除完所有的软引用时会设置该属性为true,当返回mutator时被设置成false
bool _all_soft_refs_clear;
enum Name {
CollectorPolicyKind,
TwoGenerationCollectorPolicyKind,
ConcurrentMarkSweepPolicyKind,
ASConcurrentMarkSweepPolicyKind,
G1CollectorPolicyKind
};
virtual CollectorPolicy::Name kind() {
return CollectorPolicy::CollectorPolicyKind;
}
}
//表示分代内存使用的CollectorPolicy
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class GenCollectorPolicy : public CollectorPolicy {
//gen0的内存最小值
size_t _min_gen0_size;
//gen0的内存初始值
size_t _initial_gen0_size;
//gen0的内存最大值
size_t _max_gen0_size;
//分代内存分配粒度,_gen_alignment必须被_space_alignment整除,_heap_alignment被_gen_alignment整除
size_t _gen_alignment;
//一种特殊的Generation实现
GenerationSpec **_generations;
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
bool is_tlab) {
//获取Java堆
GenCollectedHeap *gch = GenCollectedHeap::heap();
//初始化GCCause
GCCauseSetter x(gch, GCCause::_allocation_failure);
HeapWord* result = NULL;
assert(size != 0, "Precondition violated");
if (GC_locker::is_active_and_needs_gc()) {
// GC_locker是active说明还有线程处于JNI关键区未开始GC
if (!gch->is_maximal_no_gc()) {
result = expand_heap_and_allocate(size, is_tlab);
}
return result; // could be null if we are out of space
} else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) {
//incremental_collection_will_fail表示如果执行增量收集是否会失败,参考上一次增量收集的结果
//如果可以执行增量收集
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
} else {
if (Verbose && PrintGCDetails) {
gclog_or_tty->print(" :: Trying full because partial may fail :: ");
}
//执行全量的full GC
gch->do_collection(true /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
//尝试分配内存
result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
if (result != NULL) {
//分配成功
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
//分配失败,尝试扩展Java堆并分配内存
result = expand_heap_and_allocate(size, is_tlab);
if (result != NULL) {
return result;
}
//分配失败,说明已经内存不足了,这时需要强制清理软引用,强制压实Java堆,任何可能的获取可用内存的方法都会执行,尽管代价昂贵
//如果尝试失败,抛出OOM异常
{
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 */,
number_of_generations() - 1 /* max_level */);
}
//再次尝试分配内存
result = gch->attempt_allocation(size, is_tlab, false /* first_only */);
if (result != NULL) {
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
//分配失败,软引用已经清理的,标志位被置为false
assert(!should_clear_all_soft_refs(),
"Flag should have been handled and cleared prior to this point");
return NULL;
}
}
//表示一个只有两个Generation的CollectorPolicy,现有的GenCollectedHeap的所有子类都是只有两个Generation,第一个Generation相同,对应GenCollectorPolicy中新增的gen0的相关属性,第二个Generation的实现各不相同。TwoGenerationCollectorPolicy增加了第二个Generation即gen1相关的属性
//hotspot/src/share/vm/memory/collectorPolicy.hpp
class TwoGenerationCollectorPolicy : public GenCollectorPolicy {
//gen1的内存最小值
size_t _min_gen1_size;
//gen1的内存初始值
size_t _initial_gen1_size;
//gen1的内存最大值
size_t _max_gen1_size;
}
//UseAdaptiveSizePolicy为false时使用的CollectorPolicy实现.该类没有添加新的属性
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp
class ConcurrentMarkSweepPolicy : public TwoGenerationCollectorPolicy {
void ConcurrentMarkSweepPolicy::initialize_alignments() {
//初始化_space_alignment等属性
_space_alignment = _gen_alignment = (uintx)Generation::GenGrain;
_heap_alignment = compute_heap_alignment();
}
void ConcurrentMarkSweepPolicy::initialize_generations() {
//初始化_generations
_generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC,
CURRENT_PC, AllocFailStrategy::RETURN_NULL);
if (_generations == NULL)
vm_exit_during_initialization("Unable to allocate gen spec");
//UseParNewGC表示在新生代使用并发收集,默认为false
if (UseParNewGC) {
if (UseAdaptiveSizePolicy) {
_generations[0] = new GenerationSpec(Generation::ASParNew,
_initial_gen0_size, _max_gen0_size);
} else {
_generations[0] = new GenerationSpec(Generation::ParNew,
_initial_gen0_size, _max_gen0_size);
}
} else {
_generations[0] = new GenerationSpec(Generation::DefNew,
_initial_gen0_size, _max_gen0_size);
}
//UseAdaptiveSizePolicy表示使用自适应策略动态调整各代的大小,默认为true
if (UseAdaptiveSizePolicy) {
_generations[1] = new GenerationSpec(Generation::ASConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
} else {
_generations[1] = new GenerationSpec(Generation::ConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
}
if (_generations[0] == NULL || _generations[1] == NULL) {
//如果初始化失败,则退出
vm_exit_during_initialization("Unable to allocate gen spec");
}
}
int number_of_generations() { return 2; }
}
//UseAdaptiveSizePolicy为true时使用的CollectorPolicy实现.该类没有添加新的属性
//hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/cmsCollectorPolicy.hpp
class ASConcurrentMarkSweepPolicy : public ConcurrentMarkSweepPolicy {
}
垃圾收集器的初始化
根据《JVM内存池》一文中,堆内存初始化
jint Universe::initialize_heap() {
if (UseParallelGC) {
Universe::_collectedHeap = new ParallelScavengeHeap();
} else if (UseG1GC) {
G1CollectorPolicyExt* g1p = new G1CollectorPolicyExt();
g1p->initialize_all();
G1CollectedHeap* g1h = new G1CollectedHeap(g1p);
Universe::_collectedHeap = g1h;
} else {
//主要存储各种不同收集器堆的模型参数
GenCollectorPolicy *gc_policy;
if (UseSerialGC) {
gc_policy = new MarkSweepPolicy();
} else if (UseConcMarkSweepGC) {
if (UseAdaptiveSizePolicy) {
gc_policy = new ASConcurrentMarkSweepPolicy();
} else {
//cms堆的模型参数
gc_policy = new ConcurrentMarkSweepPolicy();
}
} else { // default old generation
gc_policy = new MarkSweepPolicy();
}
//根据JVM参数,对堆模型参数初始化
gc_policy->initialize_all();
Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
}
//eden中tlab表申请
ThreadLocalAllocBuffer::set_max_size(Universe::heap()->max_tlab_size());
//堆申请,及分带初始化
jint status = Universe::heap()->initialize();
if (status != JNI_OK) {
return status;
}
// .....
}
其中最常用的为cms垃圾收集器。其触发参数为
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
- Policy中根据参数设置分代数据,根据参数并行gc线程
Threads::create_vm()《openJdk的启动流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
ConcurrentMarkSweepPolicy::initialize_all
ConcurrentMarkSweepPolicy::initialize_generations # 分代数据设置
GenCollectedHeap::GenCollectedHeap
SharedHeap::SharedHeap # GC线程创建
//年轻代参数设置
_generations[0] = new GenerationSpec(Generation::ParNew,
_initial_gen0_size, _max_gen0_size);
//老年代参数设置
_generations[1] = new GenerationSpec(Generation::ConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
//初始化执行并行GC的线程池
_workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
/* are_GC_task_threads */true,
/* are_ConcurrentGC_threads */false);
- 根据分代参数,具体初始化分代
Threads::create_vm()《openJdk的启动流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
GenCollectedHeap::initialize()
//根据各GenerationSpec的最大大小计算总的需要保留的内存空间,然后申请指定大小的连续内存空间
heap_address = allocate(heap_alignment, &total_reserved,
&n_covered_regions, &heap_rs);
//分带初始化
_gen_specs[i]->init(this_rs, i, rem_set());
//年轻代
new ParNewGeneration(rs, init_size(), 0);
//老年代
new ConcurrentMarkSweepGeneration(rs,
init_size(), 1, ctrs, UseCMSAdaptiveFreeLists,
(FreeBlockDictionary<FreeChunk>::DictionaryChoice)CMSDictionaryChoice);
- 验证堆模型的正确性,及进一些初始化参数,具体参考GenCollectedHeap::post_initialize
垃圾收集触发
- 创建vm_threads,用于处理虚拟机各种延时任务
Threads::create_vm()《openJdk的启动流程》中的方法
VMThread::create()
- 编写一触放eden垃圾回收代码
/*-verbose:gc
-Xms20M
-Xmx20M
-Xmn10M
-XX:SurvivorRatio=8
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+UseConcMarkSweepGC
-XX:MaxTenuringThreshold=1*/
byte[] b1, b2, b3, b4;
b1 = new byte[2 * _1MB];
b2 = new byte[2* _1MB];
b3 = new byte[2* _1MB];
b2 = null;
b3 = null;
b4 = new byte[2* _1MB]; //eden用完,必须回收
- 内存申请失败生成VM_GenCollectForAllocation并向vm_threads提交
创建b4时通过JNI调用
InterpreterRuntime::newarray
TypeArrayKlass::allocate_common
CollectedHeap::common_mem_allocate_init
GenCollectorPolicy::mem_allocate_work
//VM_GenCollectForAllocation是内存分配失败触发垃圾回收,然后尝试分配内存的操作
VM_GenCollectForAllocation op(size, is_tlab, gc_count_before);
VMThread::execute(&op);
- VMThread处理VM_GenCollectForAllocation事件,进行垃圾回收
VMThread::run
VMThread::loop
VM_Operation::evaluate
VM_GenCollectForAllocation::doit
GenCollectorPolicy::satisfy_failed_allocation
//如果执行增量收集是否会失败,参考上一次增量收集的结果
if(!incremental_collection_will_fail(false)){
//如果可以执行增量收集
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}else{
//执行全量的full GC
gch->do_collection(true /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
- 根据上例子do_collection执行流程为
int starting_level = 0;
boolean full = false;
int max_level = 1;
//full为false,空间不充足
ParNewGeneration.should_collect() //返回true
ParNewGeneration.collect(full, do_clear_all_soft_refs, size, is_tlab);
//full为false,空间充足
ConcurrentMarkSweepGeneration.should_collect() //false
ParNew年轻代
- 年轻代初始化
Threads::create_vm()《openJdk的启动流程》中的方法
init_globals()
Universe::universe_init()
Universe::initialize_heap()
GenCollectedHeap::initialize
GenerationSpec::init
ParNewGeneration::ParNewGeneration
DefNewGeneration::DefNewGeneration
//总体申请了个_virtual_space空间
//其中又用EdenSpace,ContiguousSpace进行进一步划分
_eden_space = new EdenSpace(this);
_from_space = new ContiguousSpace();
_to_space = new ContiguousSpace();
//计算survivor区和eden区的最大空间,即年轻代最大内存时survivor区和eden区的内存空间
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);
- 年轻代对象分配主要在eden区,只有在eden区和老年代都满了,才可能在from区中分配内存,正常情况下to区是空的
数组创建时通过JNI调用
InterpreterRuntime::newarray
TypeArrayKlass::allocate_common
CollectedHeap::common_mem_allocate_init
GenCollectorPolicy::mem_allocate_work
GenCollectedHeap::attempt_allocation
DefNewGeneration::allocate
//正常请求分配eden的空间
//word_size为此次对象所要的空间
HeapWord* result = eden()->par_allocate(word_size);
if (result != NULL) {
return result;
}
//从from申请空间
result = allocate_from_space(word_size);
- 年轻代垃圾收集ParNewGeneration.collect
//FastScanClosure用来遍历年轻代中的存活对象oop,第二个参数为true,表示会将oop对应的卡表项置为youngergen_card
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用来遍历一个ClassLoader加载的所有类对应的Class实例和依赖等
CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
&fsc_with_no_gc_barrier,
false)
//上面把所有的遍历器都准备好了,遍历器的底层原理是space
//gen_process_roots用于遍历处理ClassLoaderDataGraph,Threads,Universe等组件中包含的oop,将这些oop作为根节点遍历其所引用的其他oop,根据参数还能遍历年轻代和老年代中的所有oop,遍历脏的卡表项对应的内存区域中包含的oop
gch->gen_process_roots(_level, //level就是0
true, //因为level是0,所以此参数实际无意义
true, // StrongRootsScope的active入参为true
GenCollectedHeap::SO_ScavengeCodeCache, //只遍历nmethod中的oop
GenCollectedHeap::StrongAndWeakRoots,//StrongAndWeakRoots是静态常量,值为false,表示会遍历weak root,如StringTable中的String对象
&fsc_with_no_gc_barrier,
&fsc_with_gc_barrier,
&cld_scan_closure);
- promote 操作
DefNewGeneration::collect
GenCollectedHeap::gen_process_roots
ClassLoaderDataGraph::roots_cld_do
FastScanClosure::do_oop
DefNewGeneration::copy_to_survivor_space
if (old->age() < tenuring_threshold()) {
//如果对象的年龄低于tenuring_threshold,则该在to区申请一块同样大小的内存
obj = (oop) to()->allocate_aligned(s);
}
if(obj == null){
//如果如果对象的年龄大于tenuring_threshold或者to区申请内存失败
//则尝试将该对象复制到老年代
obj = _next_gen->promote(old, s);
if (obj == NULL) {
//复制失败
handle_promotion_failure(old);
return old;
}
}else{
//to区中申请内存成功
}
//将对象头指针指向新地址
old->forward_to(obj);
//promote就是指将某个存活对象oop从eden区拷贝到from区或者老年代的过程
//如果对象年龄大于阈值则拷贝到老年代,否则拷贝到to区
//如果to区内存不足则拷贝到老年代
//如果老年代空间不足则会临时保存该oop,因为有可能是该对象较大,此时其他较小的对象可以正常promote成功的。
//从to区或者老年代按照对象大小分配好同样大小的内存后,就会将旧对象的数据复制到新分配的内存上,然后增加复制对象的对象年龄,最后将复制对象的地址写入原对象的对象头中并打标,这个动作就是forword。
CMS老年代垃圾收集
待续
主要参数
《hotspot实战》
《Hotspot 垃圾回收之VM_Operation 源码解析》
《Hotspot 垃圾回收之CollectedHeap 源码解析》
《Hotspot 垃圾回收之GenCollectedHeap 源码解析》
《Hotspot 垃圾回收之CompactibleSpace 源码解析》
《Hotspot 垃圾回收之EdenSpace 源码解析》
《Hotspot 垃圾回收之DefNewGeneration(一) 源码解析》
《Hotspot 垃圾回收之DefNewGeneration(二) 源码解析》
《Hotspot 垃圾回收之CollectorPolicy (一) 源码解析》
《Hotspot 垃圾回收之CollectorPolicy (二) 源码解析》