gc_heap::plan_phase
函数的代码如下
void gc_heap::plan_phase (int condemned_gen_number)
{
// 如果收集代是gen 1则记录原来gen 2的大小
size_t old_gen2_allocated = 0;
size_t old_gen2_size = 0;
if (condemned_gen_number == (max_generation - 1))
{
old_gen2_allocated = generation_free_list_allocated (generation_of (max_generation));
old_gen2_size = generation_size (max_generation);
}
assert (settings.concurrent == FALSE);
// 统计计划阶段的开始时间
// %type% category = quote (plan);
#ifdef TIME_GC
unsigned start;
unsigned finish;
start = GetCycleCount32();
#endif //TIME_GC
dprintf (2,("---- Plan Phase ---- Condemned generation %d, promotion: %d",
condemned_gen_number, settings.promotion ? 1 : 0));
// 收集代的对象
generation* condemned_gen1 = generation_of (condemned_gen_number);
// 判断之前是否使用了mark list
// 标记对象较少时用mark list可以提升速度
#ifdef MARK_LIST
BOOL use_mark_list = FALSE;
uint8_t** mark_list_next = &mark_list[0];
#ifdef GC_CONFIG_DRIVEN
dprintf (3, ("total number of marked objects: %Id (%Id)",
(mark_list_index - &mark_list[0]), ((mark_list_end - &mark_list[0]))));
#else
dprintf (3, ("mark_list length: %Id",
(mark_list_index - &mark_list[0])));
#endif //GC_CONFIG_DRIVEN
if ((condemned_gen_number < max_generation) &&
(mark_list_index <= mark_list_end)
#ifdef BACKGROUND_GC
&& (!recursive_gc_sync::background_running_p())
#endif //BACKGROUND_GC
)
{
#ifndef MULTIPLE_HEAPS
_sort (&mark_list[0], mark_list_index-1, 0);
//printf ("using mark list at GC #%d", dd_collection_count (dynamic_data_of (0)));
//verify_qsort_array (&mark_list[0], mark_list_index-1);
#endif //!MULTIPLE_HEAPS
use_mark_list = TRUE;
get_gc_data_per_heap()->set_mechanism_bit (gc_mark_list_bit);
}
else
{
dprintf (3, ("mark_list not used"));
}
#endif //MARK_LIST
// 清除read only segment中的marked bit
#ifdef FEATURE_BASICFREEZE
if ((generation_start_segment (condemned_gen1) != ephemeral_heap_segment) &&
ro_segments_in_range)
{
sweep_ro_segments (generation_start_segment (condemned_gen1));
}
#endif // FEATURE_BASICFREEZE
// 根据之前使用m_boundary记录的slow和shigh快速清扫slow前面和shigh后面的垃圾对象
// shigh等于0表示无对象存活
// if (shigh != (uint8_t*)0)
// 对于slow, 调用make_unused_array
// 对于shigh, 设置heap_segment_allocated
// 对于范围外的segment, heap_segment_allocated (seg) = heap_segment_mem (seg); // 整个segment都被清空,后面可删除
// else
// 第一个segment, heap_segment_allocated (seg) = generation_allocation_start (condemned_gen1);
// 后面的segment, heap_segment_allocated (seg) = heap_segment_mem (seg); // 整个segment都被清空,后面可删除
#ifndef MULTIPLE_HEAPS
if (shigh != (uint8_t*)0)
{
heap_segment* seg = heap_segment_rw (generation_start_segment (condemned_gen1));
PREFIX_ASSUME(seg != NULL);
heap_segment* fseg = seg;
do
{
if (slow > heap_segment_mem (seg) &&
slow < heap_segment_reserved (seg))
{
if (seg == fseg)
{
uint8_t* o = generation_allocation_start (condemned_gen1) +
Align (size (generation_allocation_start (condemned_gen1)));
if (slow > o)
{
assert ((slow - o) >= (int)Align (min_obj_size));
#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
bgc_clear_batch_mark_array_bits (o, slow);
}
#endif //BACKGROUND_GC
make_unused_array (o, slow - o);
}
}
else
{
assert (condemned_gen_number == max_generation);
make_unused_array (heap_segment_mem (seg),
slow - heap_segment_mem (seg));
}
}
if (in_range_for_segment (shigh, seg))
{
#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
bgc_clear_batch_mark_array_bits ((shigh + Align (size (shigh))), heap_segment_allocated (seg));
}
#endif //BACKGROUND_GC
heap_segment_allocated (seg) = shigh + Align (size (shigh));
}
// test if the segment is in the range of [slow, shigh]
if (!((heap_segment_reserved (seg) >= slow) &&
(heap_segment_mem (seg) <= shigh)))
{
// shorten it to minimum
heap_segment_allocated (seg) = heap_segment_mem (seg);
}
seg = heap_segment_next_rw (seg);
} while (seg);
}
else
{
heap_segment* seg = heap_segment_rw (generation_start_segment (condemned_gen1));
PREFIX_ASSUME(seg != NULL);
heap_segment* sseg = seg;
do
{
// shorten it to minimum
if (seg == sseg)
{
// no survivors make all generations look empty
uint8_t* o = generation_allocation_start (condemned_gen1) +
Align (size (generation_allocation_start (condemned_gen1)));
#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
bgc_clear_batch_mark_array_bits (o, heap_segment_allocated (seg));
}
#endif //BACKGROUND_GC
heap_segment_allocated (seg) = o;
}
else
{
assert (condemned_gen_number == max_generation);
#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
bgc_clear_batch_mark_array_bits (heap_segment_mem (seg), heap_segment_allocated (seg));
}
#endif //BACKGROUND_GC
heap_segment_allocated (seg) = heap_segment_mem (seg);
}
seg = heap_segment_next_rw (seg);
} while (seg);
}
#endif //MULTIPLE_HEAPS
// 当前计划的segment,会随着计划向后移动
heap_segment* seg1 = heap_segment_rw (generation_start_segment (condemned_gen1));
PREFIX_ASSUME(seg1 != NULL);
// 当前计划的segment的结束地址
uint8_t* end = heap_segment_allocated (seg1);
// 收集代的第一个对象(地址)
uint8_t* first_condemned_address = generation_allocation_start (condemned_gen1);
// 当前计划的对象
uint8_t* x = first_condemned_address;
assert (!marked (x));
// 当前plug的结束地址
uint8_t* plug_end = x;
// 当前plug树的根节点
uint8_t* tree = 0;
// 构建plug树使用的序列
size_t sequence_number = 0;
// 上一次的plug节点
uint8_t* last_node = 0;
// 当前计划的brick
size_t current_brick = brick_of (x);
// 是否从计划代开始模拟分配(这个变量后面还会设为true)
BOOL allocate_in_condemned = ((condemned_gen_number == max_generation)||
(settings.promotion == FALSE));
// 当前计划的旧代和新代,这两个变量用于重新决定代边界(generation_allocation_start)
int active_old_gen_number = condemned_gen_number;
int active_new_gen_number = (allocate_in_condemned ? condemned_gen_number:
(1 + condemned_gen_number));
// 收集代的上一代(如果收集代是gen 2这里会设为gen 2)
generation* older_gen = 0;
// 模拟分配的代
generation* consing_gen = condemned_gen1;
// older_gen的原始数据备份
alloc_list r_free_list [MAX_BUCKET_COUNT];
size_t r_free_list_space = 0;
size_t r_free_obj_space = 0;
size_t r_older_gen_free_list_allocated = 0;
size_t r_older_gen_condemned_allocated = 0;
size_t r_older_gen_end_seg_allocated = 0;
uint8_t* r_allocation_pointer = 0;
uint8_t* r_allocation_limit = 0;
uint8_t* r_allocation_start_region = 0;
heap_segment* r_allocation_segment = 0;
#ifdef FREE_USAGE_STATS
size_t r_older_gen_free_space[NUM_GEN_POWER2];
#endif //FREE_USAGE_STATS
// 在计划之前备份older_gen的数据
if ((condemned_gen_number < max_generation))
{
older_gen = generation_of (min (max_generation, 1 + condemned_gen_number));
generation_allocator (older_gen)->copy_to_alloc_list (r_free_list);
r_free_list_space = generation_free_list_space (older_gen);
r_free_obj_space = generation_free_obj_space (older_gen);
#ifdef FREE_USAGE_STATS
memcpy (r_older_gen_free_space, older_gen->gen_free_spaces, sizeof (r_older_gen_free_space));
#endif //FREE_USAGE_STATS
generation_allocate_end_seg_p (older_gen) = FALSE;
r_older_gen_free_list_allocated = generation_free_list_allocated (older_gen);
r_older_gen_condemned_allocated = generation_condemned_allocated (older_gen);
r_older_gen_end_seg_allocated = generation_end_seg_allocated (older_gen);
r_allocation_limit = generation_allocation_limit (older_gen);
r_allocation_pointer = generation_allocation_pointer (older_gen);
r_allocation_start_region = generation_allocation_context_start_region (older_gen);
r_allocation_segment = generation_allocation_segment (older_gen);
heap_segment* start_seg = heap_segment_rw (generation_start_segment (older_gen));
PREFIX_ASSUME(start_seg != NULL);
if (start_seg != ephemeral_heap_segment)
{
assert (condemned_gen_number == (max_generation - 1));
while (start_seg && (start_seg != ephemeral_heap_segment))
{
assert (heap_segment_allocated (start_seg) >=
heap_segment_mem (start_seg));
assert (heap_segment_allocated (start_seg) <=
heap_segment_reserved (start_seg));
heap_segment_plan_allocated (start_seg) =
heap_segment_allocated (start_seg);
start_seg = heap_segment_next_rw (start_seg);
}
}
}
// 重设收集代以后的的所有segment的plan_allocated(计划分配的对象大小合计)
//reset all of the segment allocated sizes
{
heap_segment* seg2 = heap_segment_rw (generation_start_segment (condemned_gen1));
PREFIX_ASSUME(seg2 != NULL);
while (seg2)
{
heap_segment_plan_allocated (seg2) =
heap_segment_mem (seg2);
seg2 = heap_segment_next_rw (seg2);
}
}
// 重设gen 0 ~ 收集代的数据
int condemned_gn = condemned_gen_number;
int bottom_gen = 0;
init_free_and_plug();
while (condemned_gn >= bottom_gen)
{
generation* condemned_gen2 = generation_of (condemned_gn);
generation_allocator (condemned_gen2)->clear();
generation_free_list_space (condemned_gen2) = 0;
generation_free_obj_space (condemned_gen2) = 0;
generation_allocation_size (condemned_gen2) = 0;
generation_condemned_allocated (condemned_gen2) = 0;
generation_pinned_allocated (condemned_gen2) = 0;
generation_free_list_allocated(condemned_gen2) = 0;
generation_end_seg_allocated (condemned_gen2) = 0;
// 执行清扫(sweep)时对应代增加的固定对象(pinned object)大小
generation_pinned_allocation_sweep_size (condemned_gen2) = 0;
// 执行压缩(compact)时对应代增加的固定对象(pinned object)大小
generation_pinned_allocation_compact_size (condemned_gen2) = 0;
#ifdef FREE_USAGE_STATS
generation_pinned_free_obj_space (condemned_gen2) = 0;
generation_allocated_in_pinned_free (condemned_gen2) = 0;
generation_allocated_since_last_pin (condemned_gen2) = 0;
#endif //FREE_USAGE_STATS
// 计划的代边界
generation_plan_allocation_start (condemned_gen2) = 0;
generation_allocation_segment (condemned_gen2) =
heap_segment_rw (generation_start_segment (condemned_gen2));
PREFIX_ASSUME(generation_allocation_segment(condemned_gen2) != NULL);
// 设置分配上下文地址,模拟压缩时使用
if (generation_start_segment (condemned_gen2) != ephemeral_heap_segment)
{
generation_allocation_pointer (condemned_gen2) =
heap_segment_mem (generation_allocation_segment (condemned_gen2));
}
else
{
generation_allocation_pointer (condemned_gen2) = generation_allocation_start (condemned_gen2);
}
generation_allocation_limit (condemned_gen2) = generation_allocation_pointer (condemned_gen2);
generation_allocation_context_start_region (condemned_gen2) = generation_allocation_pointer (condemned_gen2);
condemned_gn--;
}
// 在处理所有对象之前是否要先决定一个代的边界
// 不升代或者收集代是gen 2(Full GC)时需要
BOOL allocate_first_generation_start = FALSE;
if (allocate_in_condemned)
{
allocate_first_generation_start = TRUE;
}
dprintf(3,( " From %Ix to %Ix", (size_t)x, (size_t)end));
// 记录对象降代(原来gen 1的对象变为gen 0)的情况
// 关于不升代和降代的条件和处理将在下面解释
demotion_low = MAX_PTR;
demotion_high = heap_segment_allocated (ephemeral_heap_segment);
// 判断是否应该阻止gen 1中的固定对象降代
// 如果只是收集原因只是因为dt_low_card_table_efficiency_p则需要阻止降代
// demote_gen1_p = false时会在下面调用advance_pins_for_demotion函数
// If we are doing a gen1 only because of cards, it means we should not demote any pinned plugs
// from gen1. They should get promoted to gen2.
demote_gen1_p = !(settings.promotion &&
(settings.condemned_generation == (max_generation - 1)) &&
gen_to_condemn_reasons.is_only_condition (gen_low_card_p));
total_ephemeral_size = 0;
// 打印除错信息
print_free_and_plug ("BP");
// 打印除错信息
for (int gen_idx = 0; gen_idx <= max_generation; gen_idx++)
{
generation* temp_gen = generation_of (gen_idx);
dprintf (2, ("gen%d start %Ix, plan start %Ix",
gen_idx,
generation_allocation_start (temp_gen),
generation_plan_allocation_start (temp_gen)));
}
// 触发etw时间
BOOL fire_pinned_plug_events_p = ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, PinPlugAtGCTime);
size_t last_plug_len = 0;
// 开始模拟压缩
// 会创建plug,设置brick table和模拟plug的移动
while (1)
{
// 应该处理下个segment
if (x >= end)
{
assert (x == end);
assert (heap_segment_allocated (seg1) == end);
heap_segment_allocated (seg1) = plug_end;
// 设置brick table
current_brick = update_brick_table (tree, current_brick, x, plug_end);
dprintf (3, ("end of seg: new tree, sequence# 0"));
sequence_number = 0;
tree = 0;
// 有下一个segment,继续处理
if (heap_segment_next_rw (seg1))
{
seg1 = heap_segment_next_rw (seg1);
end = heap_segment_allocated (seg1);
plug_end = x = heap_segment_mem (seg1);
current_brick = brick_of (x);
dprintf(3,( " From %Ix to %Ix", (size_t)x, (size_t)end));
continue;
}
// 无下一个segment,跳出模拟压缩的循环
else
{
break;
}
}
// 上一个plug是否unpinned plug
BOOL last_npinned_plug_p = FALSE;
// 上一个plug是否pinned plug
BOOL last_pinned_plug_p = FALSE;
// 上一个pinned plug的地址,合并pinned plug时使用
// last_pinned_plug is the beginning of the last pinned plug. If we merge a plug into a pinned
// plug we do not change the value of last_pinned_plug. This happens with artificially pinned plugs -
// it can be merged with a previous pinned plug and a pinned plug after it can be merged with it.
uint8_t* last_pinned_plug = 0;
size_t num_pinned_plugs_in_plug = 0;
// 当前plug的最后一个对象的地址
uint8_t* last_object_in_plug = 0;
// 枚举segment中的对象,如果第一个对象未被标记不会进入以下的处理
while ((x < end) && marked (x))
{
// 记录plug的开始
uint8_t* plug_start = x;
uint8_t* saved_plug_end = plug_end;
// 当前plug中的对象是否pinned object
// 会轮流切换
BOOL pinned_plug_p = FALSE;
BOOL npin_before_pin_p = FALSE;
BOOL saved_last_npinned_plug_p = last_npinned_plug_p;
uint8_t* saved_last_object_in_plug = last_object_in_plug;
BOOL merge_with_last_pin_p = FALSE;
size_t added_pinning_size = 0;
size_t artificial_pinned_size = 0;
// 预先保存一部分plug信息
// 设置这个plug和上一个plug的结尾之间的gap
// 如果当前plug是pinned plug
// - 调用enque_pinned_plug把plug信息保存到mark_stack_array队列
// - enque_pinned_plug不会设置长度(len)和移动队列顶部(mark_stack_tos),这部分工作会在set_pinned_info完成
// - 检测当前pinned plug是否覆盖了前一个unpinned plug的结尾
// - 如果覆盖了需要把原来的内容复制到saved_pre_plug和saved_pre_plug_reloc (函数enque_pinned_plug)
// 如果当前plug是unpinned plug
// - 检测当前unpinned plug是否覆盖了前一个pinned plug的结尾
// - 如果覆盖了需要把原来的内容复制到saved_post_plug和saved_post_plug_reloc (函数save_post_plug_info)
store_plug_gap_info (plug_start, plug_end, last_npinned_plug_p, last_pinned_plug_p,
last_pinned_plug, pinned_plug_p, last_object_in_plug,
merge_with_last_pin_p, last_plug_len);
#ifdef FEATURE_STRUCTALIGN
int requiredAlignment = ((CObjectHeader*)plug_start)->GetRequiredAlignment();
size_t alignmentOffset = OBJECT_ALIGNMENT_OFFSET;
#endif // FEATURE_STRUCTALIGN
{
// 枚举接下来的对象,如果对象未被标记,或者对象是否固定和pinned_plug_p不一致则中断
// 这里枚举到的对象都会归到同一个plug里面
uint8_t* xl = x;
while ((xl < end) && marked (xl) && (pinned (xl) == pinned_plug_p))
{
assert (xl < end);
// 清除pinned bit
// 像前面所说的,GC里面marked和pinned标记都是临时使用的,在计划阶段会被清除
if (pinned(xl))
{
clear_pinned (xl);
}
#ifdef FEATURE_STRUCTALIGN
else
{
int obj_requiredAlignment = ((CObjectHeader*)xl)->GetRequiredAlignment();
if (obj_requiredAlignment > requiredAlignment)
{
requiredAlignment = obj_requiredAlignment;
alignmentOffset = xl - plug_start + OBJECT_ALIGNMENT_OFFSET;
}
}
#endif // FEATURE_STRUCTALIGN
// 清除marked bit
clear_marked (xl);
dprintf(4, ("+%Ix+", (size_t)xl));
assert ((size (xl) > 0));
assert ((size (xl) <= LARGE_OBJECT_SIZE));
// 记录当前plug的最后一个对象
last_object_in_plug = xl;
// 下一个对象
xl = xl + Align (size (xl));
Prefetch (xl);
}
BOOL next_object_marked_p = ((xl < end) && marked (xl));
// 如果当前plug是pinned plug但下一个不是,代表当前plug的结尾需要被覆盖掉做下一个plug的信息
// 我们不想动pinned plug的内容,所以这里需要牺牲下一个对象,把下一个对象拉到这个plug里面
if (pinned_plug_p)
{
// If it is pinned we need to extend to the next marked object as we can't use part of
// a pinned object to make the artificial gap (unless the last 3 ptr sized words are all
// references but for now I am just using the next non pinned object for that).
if (next_object_marked_p)
{
clear_marked (xl);
last_object_in_plug = xl;
size_t extra_size = Align (size (xl));
xl = xl + extra_size;
added_pinning_size = extra_size;
}
}
else
{
// 当前plug是unpinned plug,下一个plug是pinned plug
if (next_object_marked_p)
npin_before_pin_p = TRUE;
}
assert (xl <= end);
x = xl;
}
dprintf (3, ( "%Ix[", (size_t)x));
// 设置plug的结尾
plug_end = x;
// plug大小 = 结尾 - 开头
size_t ps = plug_end - plug_start;
last_plug_len = ps;
dprintf (3, ( "%Ix[(%Ix)", (size_t)x, ps));
uint8_t* new_address = 0;
// 有时候如果一个unpinned plug很大,我们想人工固定它(artificially pinned plug)
// 如果前一个plug也是pinned plug则和前一个plug整合到一个,否则进入mark_stack_array队列中
if (!pinned_plug_p)
{
if (allocate_in_condemned &&
(settings.condemned_generation == max_generation) &&
(ps > (OS_PAGE_SIZE)))
{
ptrdiff_t reloc = plug_start - generation_allocation_pointer (consing_gen);
//reloc should >=0 except when we relocate
//across segments and the dest seg is higher then the src
if ((ps > (8*OS_PAGE_SIZE)) &&
(reloc > 0) &&
((size_t)reloc < (ps/16)))
{
dprintf (3, ("Pinning %Ix; reloc would have been: %Ix",
(size_t)plug_start, reloc));
// The last plug couldn't have been a npinned plug or it would have
// included this plug.
assert (!saved_last_npinned_plug_p);
if (last_pinned_plug)
{
dprintf (3, ("artificially pinned plug merged with last pinned plug"));
merge_with_last_pin_p = TRUE;
}
else
{
enque_pinned_plug (plug_start, FALSE, 0);
last_pinned_plug = plug_start;
}
convert_to_pinned_plug (last_npinned_plug_p, last_pinned_plug_p, pinned_plug_p,
ps, artificial_pinned_size);
}
}
}
// 如果在做Full GC或者不升代,决定第一个代的边界
// plan_generation_start用于计划代的边界(generation_plan_generation_start)
// Full GC时gen 2的边界会在这里决定
if (allocate_first_generation_start)
{
allocate_first_generation_start = FALSE;
plan_generation_start (condemned_gen1, consing_gen, plug_start);
assert (generation_plan_allocation_start (condemned_gen1));
}
// 如果模拟的segment是ephemeral heap segment
// 在这里决定gen 1的边界
// 如果不升代这里也会决定gen 0的边界
if (seg1 == ephemeral_heap_segment)
{
process_ephemeral_boundaries (plug_start, active_new_gen_number,
active_old_gen_number,
consing_gen,
allocate_in_condemned);
}
dprintf (3, ("adding %Id to gen%d surv", ps, active_old_gen_number));
// 统计存活的对象大小
dynamic_data* dd_active_old = dynamic_data_of (active_old_gen_number);
dd_survived_size (dd_active_old) += ps;
// 模拟压缩的时候有可能会要求把当前unpinned plug转换为pinned plug
BOOL convert_to_pinned_p = FALSE;
// 如果plug是unpinned plug,模拟压缩
if (!pinned_plug_p)
{
#if defined (RESPECT_LARGE_ALIGNMENT) || defined (FEATURE_STRUCTALIGN)
dd_num_npinned_plugs (dd_active_old)++;
#endif //RESPECT_LARGE_ALIGNMENT || FEATURE_STRUCTALIGN
// 更新统计信息
add_gen_plug (active_old_gen_number, ps);
if (allocate_in_condemned)
{
verify_pins_with_post_plug_info("before aic");
// 在收集代分配,必要时跳过pinned plug,返回新的地址
new_address =
allocate_in_condemned_generations (consing_gen,
ps,
active_old_gen_number,
#ifdef SHORT_PLUGS
&convert_to_pinned_p,
(npin_before_pin_p ? plug_end : 0),
seg1,
#endif //SHORT_PLUGS
plug_start REQD_ALIGN_AND_OFFSET_ARG);
verify_pins_with_post_plug_info("after aic");
}
else
{
// 在上一代分配,必要时跳过pinned plug,返回新的地址
new_address = allocate_in_older_generation (older_gen, ps, active_old_gen_number, plug_start REQD_ALIGN_AND_OFFSET_ARG);
if (new_address != 0)
{
if (settings.condemned_generation == (max_generation - 1))
{
dprintf (3, (" NA: %Ix-%Ix -> %Ix, %Ix (%Ix)",
plug_start, plug_end,
(size_t)new_address, (size_t)new_address + (plug_end - plug_start),
(size_t)(plug_end - plug_start)));
}
}
else
{
// 失败时(空间不足)改为在收集代分配
allocate_in_condemned = TRUE;
new_address = allocate_in_condemned_generations (consing_gen, ps, active_old_gen_number,
#ifdef SHORT_PLUGS
&convert_to_pinned_p,
(npin_before_pin_p ? plug_end : 0),
seg1,
#endif //SHORT_PLUGS
plug_start REQD_ALIGN_AND_OFFSET_ARG);
}
}
// 如果要求把当前unpinned plug转换为pinned plug
if (convert_to_pinned_p)
{
assert (last_npinned_plug_p != FALSE);
assert (last_pinned_plug_p == FALSE);
convert_to_pinned_plug (last_npinned_plug_p, last_pinned_plug_p, pinned_plug_p,
ps, artificial_pinned_size);
enque_pinned_plug (plug_start, FALSE, 0);
last_pinned_plug = plug_start;
}
else
{
// 找不到空间(不移动这个plug)时验证是在ephemeral heap segment的末尾
// 这里还不会设置reloc,到下面的set_node_relocation_distance才会设
if (!new_address)
{
//verify that we are at then end of the ephemeral segment
assert (generation_allocation_segment (consing_gen) ==
ephemeral_heap_segment);
//verify that we are near the end
assert ((generation_allocation_pointer (consing_gen) + Align (ps)) <
heap_segment_allocated (ephemeral_heap_segment));
assert ((generation_allocation_pointer (consing_gen) + Align (ps)) >
(heap_segment_allocated (ephemeral_heap_segment) + Align (min_obj_size)));
}
else
{
#ifdef SIMPLE_DPRINTF
dprintf (3, ("(%Ix)[%Ix->%Ix, NA: [%Ix(%Id), %Ix[: %Ix(%d)",
(size_t)(node_gap_size (plug_start)),
plug_start, plug_end, (size_t)new_address, (size_t)(plug_start - new_address),
(size_t)new_address + ps, ps,
(is_plug_padded (plug_start) ? 1 : 0)));
#endif //SIMPLE_DPRINTF
#ifdef SHORT_PLUGS
if (is_plug_padded (plug_start))
{
dprintf (3, ("%Ix was padded", plug_start));
dd_padding_size (dd_active_old) += Align (min_obj_size);
}
#endif //SHORT_PLUGS
}
}
}
// 如果当前plug是pinned plug
if (pinned_plug_p)
{
if (fire_pinned_plug_events_p)
FireEtwPinPlugAtGCTime(plug_start, plug_end,
(merge_with_last_pin_p ? 0 : (uint8_t*)node_gap_size (plug_start)),
GetClrInstanceId());
// 和上一个pinned plug合并
if (merge_with_last_pin_p)
{
merge_with_last_pinned_plug (last_pinned_plug, ps);
}
// 设置队列中的pinned plug大小(len)并移动队列顶部(mark_stack_tos++)
else
{
assert (last_pinned_plug == plug_start);
set_pinned_info (plug_start, ps, consing_gen);
}
// pinned plug不能移动,新地址和原地址一样
new_address = plug_start;
dprintf (3, ( "(%Ix)PP: [%Ix, %Ix[%Ix](m:%d)",
(size_t)(node_gap_size (plug_start)), (size_t)plug_start,
(size_t)plug_end, ps,
(merge_with_last_pin_p ? 1 : 0)));
// 统计存活对象的大小,固定对象的大小和人工固定对象的大小
dprintf (3, ("adding %Id to gen%d pinned surv", plug_end - plug_start, active_old_gen_number));
dd_pinned_survived_size (dd_active_old) += plug_end - plug_start;
dd_added_pinned_size (dd_active_old) += added_pinning_size;
dd_artificial_pinned_survived_size (dd_active_old) += artificial_pinned_size;
// 如果需要禁止降代gen 1的对象,记录在gen 1中最后一个pinned plug的结尾
if (!demote_gen1_p && (active_old_gen_number == (max_generation - 1)))
{
last_gen1_pin_end = plug_end;
}
}
#ifdef _DEBUG
// detect forward allocation in the same segment
assert (!((new_address > plug_start) &&
(new_address < heap_segment_reserved (seg1))));
#endif //_DEBUG
// 如果不合并到上一个pinned plug
// 在这里可以设置偏移值(reloc)和更新brick table了
if (!merge_with_last_pin_p)
{
// 如果已经在下一个brick
// 把之前的plug树设置到之前的brick中,并重设plug树
// 如果之前的plug跨了多个brick,update_brick_table会设置后面的brick为-1
if (current_brick != brick_of (plug_start))
{
current_brick = update_brick_table (tree, current_brick, plug_start, saved_plug_end);
sequence_number = 0;
tree = 0;
}
// 更新plug的偏移值(reloc)
// 这里的偏移值会用在后面的重定位阶段(relocate_phase)和压缩阶段(compact_phase)
set_node_relocation_distance (plug_start, (new_address - plug_start));
// 构建plug树
if (last_node && (node_relocation_distance (last_node) ==
(node_relocation_distance (plug_start) +
(int)node_gap_size (plug_start))))
{
//dprintf(3,( " Lb"));
dprintf (3, ("%Ix Lb", plug_start));
set_node_left (plug_start);
}
if (0 == sequence_number)
{
dprintf (2, ("sn: 0, tree is set to %Ix", plug_start));
tree = plug_start;
}
verify_pins_with_post_plug_info("before insert node");
tree = insert_node (plug_start, ++sequence_number, tree, last_node);
dprintf (3, ("tree is %Ix (b: %Ix) after insert_node", tree, brick_of (tree)));
last_node = plug_start;
// 这个处理只用于除错
// 如果这个plug是unpinned plug并且覆盖了上一个pinned plug的结尾
// 把覆盖的内容复制到pinned plug关联的saved_post_plug_debug
#ifdef _DEBUG
// If we detect if the last plug is pinned plug right before us, we should save this gap info
if (!pinned_plug_p)
{
if (mark_stack_tos > 0)
{
mark& m = mark_stack_array[mark_stack_tos - 1];
if (m.has_post_plug_info())
{
uint8_t* post_plug_info_start = m.saved_post_plug_info_start;
size_t* current_plug_gap_start = (size_t*)(plug_start - sizeof (plug_and_gap));
if ((uint8_t*)current_plug_gap_start == post_plug_info_start)
{
dprintf (3, ("Ginfo: %Ix, %Ix, %Ix",
*current_plug_gap_start, *(current_plug_gap_start + 1),
*(current_plug_gap_start + 2)));
memcpy (&(m.saved_post_plug_debug), current_plug_gap_start, sizeof (gap_reloc_pair));
}
}
}
}
#endif //_DEBUG
verify_pins_with_post_plug_info("after insert node");
}
}
if (num_pinned_plugs_in_plug > 1)
{
dprintf (3, ("more than %Id pinned plugs in this plug", num_pinned_plugs_in_plug));
}
// 跳过未标记的对象找到下一个已标记的对象
// 如果有mark_list可以加快找到下一个已标记对象的速度
{
#ifdef MARK_LIST
if (use_mark_list)
{
while ((mark_list_next < mark_list_index) &&
(*mark_list_next <= x))
{
mark_list_next++;
}
if ((mark_list_next < mark_list_index)
#ifdef MULTIPLE_HEAPS
&& (*mark_list_next < end) //for multiple segments
#endif //MULTIPLE_HEAPS
)
x = *mark_list_next;
else
x = end;
}
else
#endif //MARK_LIST
{
uint8_t* xl = x;
#ifdef BACKGROUND_GC
if (current_c_gc_state == c_gc_state_marking)
{
assert (recursive_gc_sync::background_running_p());
while ((xl < end) && !marked (xl))
{
dprintf (4, ("-%Ix-", (size_t)xl));
assert ((size (xl) > 0));
background_object_marked (xl, TRUE);
xl = xl + Align (size (xl));
Prefetch (xl);
}
}
else
#endif //BACKGROUND_GC
{
// 跳过未标记的对象
while ((xl < end) && !marked (xl))
{
dprintf (4, ("-%Ix-", (size_t)xl));
assert ((size (xl) > 0));
xl = xl + Align (size (xl));
Prefetch (xl);
}
}
assert (xl <= end);
// 找到了下一个已标记的对象,或者当前segment中的对象已经搜索完毕
x = xl;
}
}
}
// 处理mark_stack_array中尚未出队的pinned plug
// 这些plug已经在所有已压缩的unpinned plug后面,我们可以把这些pinned plug降级(降到gen 0),也可以防止它们降级
while (!pinned_plug_que_empty_p())
{
// 计算代边界和处理降代
// 不在ephemeral heap segment的pinned plug不会被降代
// 前面调用的process_ephemeral_boundaries中有相同的处理
if (settings.promotion)
{
uint8_t* pplug = pinned_plug (oldest_pin());
if (in_range_for_segment (pplug, ephemeral_heap_segment))
{
consing_gen = ensure_ephemeral_heap_segment (consing_gen);
//allocate all of the generation gaps
while (active_new_gen_number > 0)
{
active_new_gen_number--;
if (active_new_gen_number == (max_generation - 1))
{
// 如果要防止gen 1的pinned plug降代则需要调用调用advance_pins_for_demotion跳过(出队)它们
// 在原来gen 0中的pinned plug不会改变
maxgen_pinned_compact_before_advance = generation_pinned_allocation_compact_size (generation_of (max_generation));
if (!demote_gen1_p)
advance_pins_for_demotion (consing_gen);
}
// 计划剩余的代边界
generation* gen = generation_of (active_new_gen_number);
plan_generation_start (gen, consing_gen, 0);
// 代边界被设置到pinned plug之前的时候需要记录降代的范围(降代已经实际发生,设置demotion_low是记录降代的范围)
if (demotion_low == MAX_PTR)
{
demotion_low = pplug;
dprintf (3, ("end plan: dlow->%Ix", demotion_low));
}
dprintf (2, ("(%d)gen%d plan start: %Ix",
heap_number, active_new_gen_number, (size_t)generation_plan_allocation_start (gen)));
assert (generation_plan_allocation_start (gen));
}
}
}
// 所有pinned plug都已出队时跳出
if (pinned_plug_que_empty_p())
break;
// 出队一个pinned plug
size_t entry = deque_pinned_plug();
mark* m = pinned_plug_of (entry);
uint8_t* plug = pinned_plug (m);
size_t len = pinned_len (m);
// 检测这个pinned plug是否在cosing_gen的allocation segment之外
// 如果不在需要调整allocation segment,等会需要把generation_allocation_pointer设置为plug + len
// detect pinned block in different segment (later) than
// allocation segment
heap_segment* nseg = heap_segment_rw (generation_allocation_segment (consing_gen));
while ((plug < generation_allocation_pointer (consing_gen)) ||
(plug >= heap_segment_allocated (nseg)))
{
assert ((plug < heap_segment_mem (nseg)) ||
(plug > heap_segment_reserved (nseg)));
//adjust the end of the segment to be the end of the plug
assert (generation_allocation_pointer (consing_gen)>=
heap_segment_mem (nseg));
assert (generation_allocation_pointer (consing_gen)<=
heap_segment_committed (nseg));
heap_segment_plan_allocated (nseg) =
generation_allocation_pointer (consing_gen);
//switch allocation segment
nseg = heap_segment_next_rw (nseg);
generation_allocation_segment (consing_gen) = nseg;
//reset the allocation pointer and limits
generation_allocation_pointer (consing_gen) =
heap_segment_mem (nseg);
}
// 出队以后设置len = pinned plug - generation_allocation_pointer (consing_gen)
// 表示pinned plug的开始地址离最后的模拟压缩分配地址的空间,这个空间可以变成free object
set_new_pin_info (m, generation_allocation_pointer (consing_gen));
dprintf (2, ("pin %Ix b: %Ix->%Ix", plug, brick_of (plug),
(size_t)(brick_table[brick_of (plug)])));
// 设置模拟压缩分配地址到plug的结尾
generation_allocation_pointer (consing_gen) = plug + len;
generation_allocation_limit (consing_gen) =
generation_allocation_pointer (consing_gen);
//Add the size of the pinned plug to the right pinned allocations
//find out which gen this pinned plug came from
int frgn = object_gennum (plug);
// 统计清扫时会多出的pinned object大小
// 加到上一代中(pinned object升代)
if ((frgn != (int)max_generation) && settings.promotion)
{
generation_pinned_allocation_sweep_size ((generation_of (frgn +1))) += len;
}
}
// 计划剩余所有代的边界
// 大部分情况下(升代 + 无降代)这里会设置gen 0的边界,也就是在现有的所有存活对象之后
plan_generation_starts (consing_gen);
// 打印除错信息
print_free_and_plug ("AP");
// 打印除错信息
{
#ifdef SIMPLE_DPRINTF
for (int gen_idx = 0; gen_idx <= max_generation; gen_idx++)
{
generation* temp_gen = generation_of (gen_idx);
dynamic_data* temp_dd = dynamic_data_of (gen_idx);
int added_pinning_ratio = 0;
int artificial_pinned_ratio = 0;
if (dd_pinned_survived_size (temp_dd) != 0)
{
added_pinning_ratio = (int)((float)dd_added_pinned_size (temp_dd) * 100 / (float)dd_pinned_survived_size (temp_dd));
artificial_pinned_ratio = (int)((float)dd_artificial_pinned_survived_size (temp_dd) * 100 / (float)dd_pinned_survived_size (temp_dd));
}
size_t padding_size =
#ifdef SHORT_PLUGS
dd_padding_size (temp_dd);
#else
0;
#endif //SHORT_PLUGS
dprintf (1, ("gen%d: %Ix, %Ix(%Id), NON PIN alloc: %Id, pin com: %Id, sweep: %Id, surv: %Id, pinsurv: %Id(%d%% added, %d%% art), np surv: %Id, pad: %Id",
gen_idx,
generation_allocation_start (temp_gen),
generation_plan_allocation_start (temp_gen),
(size_t)(generation_plan_allocation_start (temp_gen) - generation_allocation_start (temp_gen)),
generation_allocation_size (temp_gen),
generation_pinned_allocation_compact_size (temp_gen),
generation_pinned_allocation_sweep_size (temp_gen),
dd_survived_size (temp_dd),
dd_pinned_survived_size (temp_dd),
added_pinning_ratio,
artificial_pinned_ratio,
(dd_survived_size (temp_dd) - dd_pinned_survived_size (temp_dd)),
padding_size));
}
#endif //SIMPLE_DPRINTF
}
// 继续打印除错信息,并且更新gen 2的统计信息
if (settings.condemned_generation == (max_generation - 1 ))
{
size_t plan_gen2_size = generation_plan_size (max_generation);
size_t growth = plan_gen2_size - old_gen2_size;
if (growth > 0)
{
dprintf (1, ("gen2 grew %Id (end seg alloc: %Id, gen1 c alloc: %Id",
growth, generation_end_seg_allocated (generation_of (max_generation)),
generation_condemned_allocated (generation_of (max_generation - 1))));
}
else
{
dprintf (1, ("gen2 shrank %Id (end seg alloc: %Id, gen1 c alloc: %Id",
(old_gen2_size - plan_gen2_size), generation_end_seg_allocated (generation_of (max_generation)),
generation_condemned_allocated (generation_of (max_generation - 1))));
}
generation* older_gen = generation_of (settings.condemned_generation + 1);
size_t rejected_free_space = generation_free_obj_space (older_gen) - r_free_obj_space;
size_t free_list_allocated = generation_free_list_allocated (older_gen) - r_older_gen_free_list_allocated;
size_t end_seg_allocated = generation_end_seg_allocated (older_gen) - r_older_gen_end_seg_allocated;
size_t condemned_allocated = generation_condemned_allocated (older_gen) - r_older_gen_condemned_allocated;
dprintf (1, ("older gen's free alloc: %Id->%Id, seg alloc: %Id->%Id, condemned alloc: %Id->%Id",
r_older_gen_free_list_allocated, generation_free_list_allocated (older_gen),
r_older_gen_end_seg_allocated, generation_end_seg_allocated (older_gen),
r_older_gen_condemned_allocated, generation_condemned_allocated (older_gen)));
dprintf (1, ("this GC did %Id free list alloc(%Id bytes free space rejected), %Id seg alloc and %Id condemned alloc, gen1 condemned alloc is %Id",
free_list_allocated, rejected_free_space, end_seg_allocated,
condemned_allocated, generation_condemned_allocated (generation_of (settings.condemned_generation))));
maxgen_size_increase* maxgen_size_info = &(get_gc_data_per_heap()->maxgen_size_info);
maxgen_size_info->free_list_allocated = free_list_allocated;
maxgen_size_info->free_list_rejected = rejected_free_space;
maxgen_size_info->end_seg_allocated = end_seg_allocated;
maxgen_size_info->condemned_allocated = condemned_allocated;
maxgen_size_info->pinned_allocated = maxgen_pinned_compact_before_advance;
maxgen_size_info->pinned_allocated_advance = generation_pinned_allocation_compact_size (generation_of (max_generation)) - maxgen_pinned_compact_before_advance;
#ifdef FREE_USAGE_STATS
int free_list_efficiency = 0;
if ((free_list_allocated + rejected_free_space) != 0)
free_list_efficiency = (int)(((float) (free_list_allocated) / (float)(free_list_allocated + rejected_free_space)) * (float)100);
int running_free_list_efficiency = (int)(generation_allocator_efficiency(older_gen)*100);
dprintf (1, ("gen%d free list alloc effi: %d%%, current effi: %d%%",
older_gen->gen_num,
free_list_efficiency, running_free_list_efficiency));
dprintf (1, ("gen2 free list change"));
for (int j = 0; j < NUM_GEN_POWER2; j++)
{
dprintf (1, ("[h%d][#%Id]: 2^%d: F: %Id->%Id(%Id), P: %Id",
heap_number,
settings.gc_index,
(j + 10), r_older_gen_free_space[j], older_gen->gen_free_spaces[j],
(ptrdiff_t)(r_older_gen_free_space[j] - older_gen->gen_free_spaces[j]),
(generation_of(max_generation - 1))->gen_plugs[j]));
}
#endif //FREE_USAGE_STATS
}
// 计算碎片空间大小fragmentation
// 这个是判断是否要压缩的依据之一
// 算法简略如下
// frag = (heap_segment_allocated(ephemeral_heap_segment) - generation_allocation_pointer (consing_gen))
// for segment in non_ephemeral_segments
// frag += heap_segment_allocated (seg) - heap_segment_plan_allocated (seg)
// for plug in dequed_plugs
// frag += plug.len
size_t fragmentation =
generation_fragmentation (generation_of (condemned_gen_number),
consing_gen,
heap_segment_allocated (ephemeral_heap_segment));
dprintf (2,("Fragmentation: %Id", fragmentation));
dprintf (2,("---- End of Plan phase ----"));
// 统计计划阶段的结束时间
#ifdef TIME_GC
finish = GetCycleCount32();
plan_time = finish - start;
#endif //TIME_GC
// We may update write barrier code. We assume here EE has been suspended if we are on a GC thread.
assert(GCHeap::IsGCInProgress());
// 是否要扩展(使用新的segment heap segment)
BOOL should_expand = FALSE;
// 是否要压缩
BOOL should_compact= FALSE;
ephemeral_promotion = FALSE;
// 如果内存太小应该强制开启压缩
#ifdef BIT64
if ((!settings.concurrent) &&
((condemned_gen_number < max_generation) &&
((settings.gen0_reduction_count > 0) || (settings.entry_memory_load >= 95))))
{
dprintf (2, ("gen0 reduction count is %d, condemning %d, mem load %d",
settings.gen0_reduction_count,
condemned_gen_number,
settings.entry_memory_load));
should_compact = TRUE;
get_gc_data_per_heap()->set_mechanism (gc_heap_compact,
((settings.gen0_reduction_count > 0) ? compact_fragmented_gen0 : compact_high_mem_load));
// 如果ephemeal heap segment空间较少应该换一个新的segment
if ((condemned_gen_number >= (max_generation - 1)) &&
dt_low_ephemeral_space_p (tuning_deciding_expansion))
{
dprintf (2, ("Not enough space for all ephemeral generations with compaction"));
should_expand = TRUE;
}
}
else
{
#endif // BIT64
// 判断是否要压缩
// 请看下面函数decide_on_compacting的代码解释
should_compact = decide_on_compacting (condemned_gen_number, fragmentation, should_expand);
#ifdef BIT64
}
#endif // BIT64
// 判断是否要压缩大对象的堆
#ifdef FEATURE_LOH_COMPACTION
loh_compacted_p = FALSE;
#endif //FEATURE_LOH_COMPACTION
if (condemned_gen_number == max_generation)
{
#ifdef FEATURE_LOH_COMPACTION
if (settings.loh_compaction)
{
// 针对大对象的堆模拟压缩,和前面创建plug计算reloc的处理差不多,但是一个plug中只有一个对象,也不会有plug树
// 保存plug信息使用的类型是loh_obj_and_pad
if (plan_loh())
{
should_compact = TRUE;
get_gc_data_per_heap()->set_mechanism (gc_heap_compact, compact_loh_forced);
loh_compacted_p = TRUE;
}
}
else
{
// 清空loh_pinned_queue
if ((heap_number == 0) && (loh_pinned_queue))
{
loh_pinned_queue_decay--;
if (!loh_pinned_queue_decay)
{
delete loh_pinned_queue;
loh_pinned_queue = 0;
}
}
}
// 如果不需要压缩大对象的堆,在这里执行清扫
// 把未标记的对象合并到一个free object并且加到free list中
// 请参考后面sweep phase的代码解释
if (!loh_compacted_p)
#endif //FEATURE_LOH_COMPACTION
{
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
if (ShouldTrackMovementForProfilerOrEtw())
notify_profiler_of_surviving_large_objects();
#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
sweep_large_objects();
}
}
else
{
settings.loh_compaction = FALSE;
}
#ifdef MULTIPLE_HEAPS
// 如果存在多个heap(服务器GC)还需要投票重新决定should_compact和should_expand
// 这里的一些处理(例如删除大对象segment和设置settings.demotion)是服务器GC和工作站GC都会做的
new_heap_segment = NULL;
if (should_compact && should_expand)
gc_policy = policy_expand;
else if (should_compact)
gc_policy = policy_compact;
else
gc_policy = policy_sweep;
//vote for result of should_compact
dprintf (3, ("Joining for compaction decision"));
gc_t_join.join(this, gc_join_decide_on_compaction);
if (gc_t_join.joined())
{
// 删除空的(无存活对象的)大对象segment
//safe place to delete large heap segments
if (condemned_gen_number == max_generation)
{
for (int i = 0; i < n_heaps; i++)
{
g_heaps [i]->rearrange_large_heap_segments ();
}
}
settings.demotion = FALSE;
int pol_max = policy_sweep;
#ifdef GC_CONFIG_DRIVEN
BOOL is_compaction_mandatory = FALSE;
#endif //GC_CONFIG_DRIVEN
int i;
for (i = 0; i < n_heaps; i++)
{
if (pol_max < g_heaps[i]->gc_policy)
pol_max = policy_compact;
// set the demotion flag is any of the heap has demotion
if (g_heaps[i]->demotion_high >= g_heaps[i]->demotion_low)
{
(g_heaps[i]->get_gc_data_per_heap())->set_mechanism_bit (gc_demotion_bit);
settings.demotion = TRUE;
}
#ifdef GC_CONFIG_DRIVEN
if (!is_compaction_mandatory)
{
int compact_reason = (g_heaps[i]->get_gc_data_per_heap())->get_mechanism (gc_heap_compact);
if (compact_reason >= 0)
{
if (gc_heap_compact_reason_mandatory_p[compact_reason])
is_compaction_mandatory = TRUE;
}
}
#endif //GC_CONFIG_DRIVEN
}
#ifdef GC_CONFIG_DRIVEN
if (!is_compaction_mandatory)
{
// If compaction is not mandatory we can feel free to change it to a sweeping GC.
// Note that we may want to change this to only checking every so often instead of every single GC.
if (should_do_sweeping_gc (pol_max >= policy_compact))
{
pol_max = policy_sweep;
}
else
{
if (pol_max == policy_sweep)
pol_max = policy_compact;
}
}
#endif //GC_CONFIG_DRIVEN
for (i = 0; i < n_heaps; i++)
{
if (pol_max > g_heaps[i]->gc_policy)
g_heaps[i]->gc_policy = pol_max;
//get the segment while we are serialized
if (g_heaps[i]->gc_policy == policy_expand)
{
g_heaps[i]->new_heap_segment =
g_heaps[i]->soh_get_segment_to_expand();
if (!g_heaps[i]->new_heap_segment)
{
set_expand_in_full_gc (condemned_gen_number);
//we are out of memory, cancel the expansion
g_heaps[i]->gc_policy = policy_compact;
}
}
}
BOOL is_full_compacting_gc = FALSE;
if ((gc_policy >= policy_compact) && (condemned_gen_number == max_generation))
{
full_gc_counts[gc_type_compacting]++;
is_full_compacting_gc = TRUE;
}
for (i = 0; i < n_heaps; i++)
{
//copy the card and brick tables
if (g_card_table!= g_heaps[i]->card_table)
{
g_heaps[i]->copy_brick_card_table();
}
if (is_full_compacting_gc)
{
g_heaps[i]->loh_alloc_since_cg = 0;
}
}
//start all threads on the roots.
dprintf(3, ("Starting all gc threads after compaction decision"));
gc_t_join.restart();
}
//reset the local variable accordingly
should_compact = (gc_policy >= policy_compact);
should_expand = (gc_policy >= policy_expand);
#else //MULTIPLE_HEAPS
// 删除空的(无存活对象的)大对象segment
//safe place to delete large heap segments
if (condemned_gen_number == max_generation)
{
rearrange_large_heap_segments ();
}
// 如果有对象被降代,则设置settings.demotion = true
settings.demotion = ((demotion_high >= demotion_low) ? TRUE : FALSE);
if (settings.demotion)
get_gc_data_per_heap()->set_mechanism_bit (gc_demotion_bit);
// 如果压缩不是必须的,根据用户提供的特殊设置重新设置should_compact
#ifdef GC_CONFIG_DRIVEN
BOOL is_compaction_mandatory = FALSE;
int compact_reason = get_gc_data_per_heap()->get_mechanism (gc_heap_compact);
if (compact_reason >= 0)
is_compaction_mandatory = gc_heap_compact_reason_mandatory_p[compact_reason];
if (!is_compaction_mandatory)
{
if (should_do_sweeping_gc (should_compact))
should_compact = FALSE;
else
should_compact = TRUE;
}
#endif //GC_CONFIG_DRIVEN
if (should_compact && (condemned_gen_number == max_generation))
{
full_gc_counts[gc_type_compacting]++;
loh_alloc_since_cg = 0;
}
#endif //MULTIPLE_HEAPS
// 进入重定位和压缩阶段
if (should_compact)
{
dprintf (2,( "**** Doing Compacting GC ****"));
// 如果应该使用新的ephemeral heap segment,调用expand_heap
// expand_heap有可能会复用前面的segment,也有可能重新生成一个segment
if (should_expand)
{
#ifndef MULTIPLE_HEAPS
heap_segment* new_heap_segment = soh_get_segment_to_expand();
#endif //!MULTIPLE_HEAPS
if (new_heap_segment)
{
consing_gen = expand_heap(condemned_gen_number,
consing_gen,
new_heap_segment);
}
// If we couldn't get a new segment, or we were able to
// reserve one but no space to commit, we couldn't
// expand heap.
if (ephemeral_heap_segment != new_heap_segment)
{
set_expand_in_full_gc (condemned_gen_number);
should_expand = FALSE;
}
}
generation_allocation_limit (condemned_gen1) =
generation_allocation_pointer (condemned_gen1);
if ((condemned_gen_number < max_generation))
{
generation_allocator (older_gen)->commit_alloc_list_changes();
// 如果 generation_allocation_limit 等于 heap_segment_plan_allocated
// 设置 heap_segment_plan_allocated 等于 generation_allocation_pointer
// 设置 generation_allocation_limit 等于 generation_allocation_pointer
// 否则
// 在alloc_ptr到limit的空间创建一个free object, 不加入free list
// Fix the allocation area of the older generation
fix_older_allocation_area (older_gen);
}
assert (generation_allocation_segment (consing_gen) ==
ephemeral_heap_segment);
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
if (ShouldTrackMovementForProfilerOrEtw())
{
record_survived_for_profiler(condemned_gen_number, first_condemned_address);
}
#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
// 调用重定位阶段
// 这里会修改所有需要移动的对象的指针地址,但是不会移动它们的内容
// 具体代码请看后面
relocate_phase (condemned_gen_number, first_condemned_address);
// 调用压缩阶段
// 这里会复制对象的内容到它们移动到的地址
// 具体代码请看后面
compact_phase (condemned_gen_number, first_condemned_address,
(!settings.demotion && settings.promotion));
// fix_generation_bounds做的事情如下
// - 应用各个代的计划代边界
// - generation_allocation_start (gen) = generation_plan_allocation_start (gen)
// - generation_allocation_pointer (gen) = 0;
// - generation_allocation_limit (gen) = 0;
// - 代边界的开始会留一段min_obj_size的空间,把这段空间变为free object
// - 如果ephemeral segment已改变则设置旧ephemeral segment的start到allocated的整个范围到Card Table
// - 设置ephemeral_heap_segment的allocated到plan_allocated
fix_generation_bounds (condemned_gen_number, consing_gen);
assert (generation_allocation_limit (youngest_generation) ==
generation_allocation_pointer (youngest_generation));
// 删除空的(无存活对象的)小对象segment
// 修复segment链表,如果ephemeral heap segment因为expand_heap改变了这里会重新正确的链接各个segment
// 修复segment的处理
// - 如果segment的next是null且堆段不是ephemeral segment, 则next = ephemeral segment
// - 如果segment是ephemeral_heap_segment并且有next, 则单独把这个segment抽出来(prev.next = next)
// - 调用delete_heap_segment删除无存活对象的segment
// - 设置heap_segment_allocated (seg) = heap_segment_plan_allocated (seg)
// - 如果segment不是ephemeral segment, 则调用decommit_heap_segment_pages释放allocated到committed的内存
if (condemned_gen_number >= (max_generation -1))
{
#ifdef MULTIPLE_HEAPS
// this needs be serialized just because we have one
// segment_standby_list/seg_table for all heaps. We should make it at least
// so that when hoarding is not on we don't need this join because
// decommitting memory can take a long time.
//must serialize on deleting segments
gc_t_join.join(this, gc_join_rearrange_segs_compaction);
if (gc_t_join.joined())
{
for (int i = 0; i < n_heaps; i++)
{
g_heaps[i]->rearrange_heap_segments(TRUE);
}
gc_t_join.restart();
}
#else
rearrange_heap_segments(TRUE);
#endif //MULTIPLE_HEAPS
// 重新设置第0代和第1代的generation_start_segment和generation_allocation_segment到新的ephemeral_heap_segment
if (should_expand)
{
//fix the start_segment for the ephemeral generations
for (int i = 0; i < max_generation; i++)
{
generation* gen = generation_of (i);
generation_start_segment (gen) = ephemeral_heap_segment;
generation_allocation_segment (gen) = ephemeral_heap_segment;
}
}
}
{
// 因为析构队列中的对象分代储存,这里根据升代或者降代移动析构队列中的对象
#ifdef FEATURE_PREMORTEM_FINALIZATION
finalize_queue->UpdatePromotedGenerations (condemned_gen_number,
(!settings.demotion && settings.promotion));
#endif // FEATURE_PREMORTEM_FINALIZATION
#ifdef MULTIPLE_HEAPS
dprintf(3, ("Joining after end of compaction"));
gc_t_join.join(this, gc_join_adjust_handle_age_compact);
if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
{
#ifdef MULTIPLE_HEAPS
//join all threads to make sure they are synchronized
dprintf(3, ("Restarting after Promotion granted"));
gc_t_join.restart();
#endif //MULTIPLE_HEAPS
}
// 更新GC Handle表中记录的代数
// GcPromotionsGranted的处理:
// 调用 Ref_AgeHandles(condemned, max_gen, (uintptr_t)sc)
// GcDemote的处理:
// 调用 Ref_RejuvenateHandles (condemned, max_gen, (uintptr_t)sc)
// Ref_AgeHandles的处理:
// 扫描g_HandleTableMap中的HandleTable, 逐个调用 BlockAgeBlocks
// BlockAgeBlocks会增加rgGeneration+uBlock~uCount中的数字
// 0x00ffffff => 0x01ffffff => 0x02ffffff
// #define COMPUTE_AGED_CLUMPS(gen, msk) APPLY_CLUMP_ADDENDS(gen, COMPUTE_CLUMP_ADDENDS(gen, msk))
// #define COMPUTE_AGED_CLUMPS(gen, msk) gen + COMPUTE_CLUMP_ADDENDS(gen, msk)
// #define COMPUTE_AGED_CLUMPS(gen, msk) gen + MAKE_CLUMP_MASK_ADDENDS(COMPUTE_CLUMP_MASK(gen, msk))
// #define COMPUTE_AGED_CLUMPS(gen, msk) gen + MAKE_CLUMP_MASK_ADDENDS((((gen & GEN_CLAMP) - msk) & GEN_MASK))
// #define COMPUTE_AGED_CLUMPS(gen, msk) gen + (((((gen & GEN_CLAMP) - msk) & GEN_MASK)) >> GEN_INC_SHIFT)
// #define COMPUTE_AGED_CLUMPS(gen, msk) gen + (((((gen & 0x3F3F3F3F) - msk) & 0x40404040)) >> 6)
// #define GEN_FULLGC PREFOLD_FILL_INTO_AGEMASK(GEN_AGE_LIMIT)
// #define GEN_FULLGC PREFOLD_FILL_INTO_AGEMASK(0x3E3E3E3E)
// #define GEN_FULLGC (1 + (0x3E3E3E3E) + (~GEN_FILL))
// #define GEN_FULLGC (1 + (0x3E3E3E3E) + (~0x80808080))
// #define GEN_FULLGC 0xbfbfbfbe
// Ref_RejuvenateHandles的处理:
// 扫描g_HandleTableMap中的HandleTable, 逐个调用 BlockResetAgeMapForBlocks
// BlockAgeBlocks会减少rgGeneration+uBlock~uCount中的数字
// 取决于该block中的handle中最年轻的代数
// rgGeneration
// 一个block对应4 byte, 第一个byte代表该block中的GCHandle的代
ScanContext sc;
sc.thread_number = heap_number;
sc.promotion = FALSE;
sc.concurrent = FALSE;
// new generations bounds are set can call this guy
if (settings.promotion && !settings.demotion)
{
dprintf (2, ("Promoting EE roots for gen %d",
condemned_gen_number));
GCScan::GcPromotionsGranted(condemned_gen_number,
max_generation, &sc);
}
else if (settings.demotion)
{
dprintf (2, ("Demoting EE roots for gen %d",
condemned_gen_number));
GCScan::GcDemote (condemned_gen_number, max_generation, &sc);
}
}
// 把各个pinned plug前面的空余空间(出队后的len)变为free object并加到free list中
{
gen0_big_free_spaces = 0;
// 队列底部等于0
reset_pinned_queue_bos();
unsigned int gen_number = min (max_generation, 1 + condemned_gen_number);
generation* gen = generation_of (gen_number);
uint8_t* low = generation_allocation_start (generation_of (gen_number-1));
uint8_t* high = heap_segment_allocated (ephemeral_heap_segment);
while (!pinned_plug_que_empty_p())
{
// 出队
mark* m = pinned_plug_of (deque_pinned_plug());
size_t len = pinned_len (m);
uint8_t* arr = (pinned_plug (m) - len);
dprintf(3,("free [%Ix %Ix[ pin",
(size_t)arr, (size_t)arr + len));
if (len != 0)
{
// 在pinned plug前的空余空间创建free object
assert (len >= Align (min_obj_size));
make_unused_array (arr, len);
// fix fully contained bricks + first one
// if the array goes beyong the first brick
size_t start_brick = brick_of (arr);
size_t end_brick = brick_of (arr + len);
// 如果free object横跨多个brick,更新brick表
if (end_brick != start_brick)
{
dprintf (3,
("Fixing bricks [%Ix, %Ix[ to point to unused array %Ix",
start_brick, end_brick, (size_t)arr));
set_brick (start_brick,
arr - brick_address (start_brick));
size_t brick = start_brick+1;
while (brick < end_brick)
{
set_brick (brick, start_brick - brick);
brick++;
}
}
// 判断要加到哪个代的free list中
//when we take an old segment to make the new
//ephemeral segment. we can have a bunch of
//pinned plugs out of order going to the new ephemeral seg
//and then the next plugs go back to max_generation
if ((heap_segment_mem (ephemeral_heap_segment) <= arr) &&
(heap_segment_reserved (ephemeral_heap_segment) > arr))
{
while ((low <= arr) && (high > arr))
{
gen_number--;
assert ((gen_number >= 1) || (demotion_low != MAX_PTR) ||
settings.demotion || !settings.promotion);
dprintf (3, ("new free list generation %d", gen_number));
gen = generation_of (gen_number);
if (gen_number >= 1)
low = generation_allocation_start (generation_of (gen_number-1));
else
low = high;
}
}
else
{
dprintf (3, ("new free list generation %d", max_generation));
gen_number = max_generation;
gen = generation_of (gen_number);
}
// 加到free list中
dprintf(3,("threading it into generation %d", gen_number));
thread_gap (arr, len, gen);
add_gen_free (gen_number, len);
}
}
}
#ifdef _DEBUG
for (int x = 0; x <= max_generation; x++)
{
assert (generation_allocation_start (generation_of (x)));
}
#endif //_DEBUG
// 如果已经升代了,原来gen 0的对象会变为gen 1
// 清理当前gen 1在Card Table中的标记
if (!settings.demotion && settings.promotion)
{
//clear card for generation 1. generation 0 is empty
clear_card_for_addresses (
generation_allocation_start (generation_of (1)),
generation_allocation_start (generation_of (0)));
}
// 如果已经升代了,确认代0的只包含一个对象(一个最小大小的free object)
if (settings.promotion && !settings.demotion)
{
uint8_t* start = generation_allocation_start (youngest_generation);
MAYBE_UNUSED_VAR(start);
assert (heap_segment_allocated (ephemeral_heap_segment) ==
(start + Align (size (start))));
}
}
// 进入清扫阶段
// 清扫阶段的关键处理在make_free_lists中,目前你看不到叫`sweep_phase`的函数,这里就是sweep phase
else
{
// 清扫阶段必须升代
//force promotion for sweep
settings.promotion = TRUE;
settings.compaction = FALSE;
ScanContext sc;
sc.thread_number = heap_number;
sc.promotion = FALSE;
sc.concurrent = FALSE;
dprintf (2, ("**** Doing Mark and Sweep GC****"));
// 恢复对旧代成员的备份
if ((condemned_gen_number < max_generation))
{
generation_allocator (older_gen)->copy_from_alloc_list (r_free_list);
generation_free_list_space (older_gen) = r_free_list_space;
generation_free_obj_space (older_gen) = r_free_obj_space;
generation_free_list_allocated (older_gen) = r_older_gen_free_list_allocated;
generation_end_seg_allocated (older_gen) = r_older_gen_end_seg_allocated;
generation_condemned_allocated (older_gen) = r_older_gen_condemned_allocated;
generation_allocation_limit (older_gen) = r_allocation_limit;
generation_allocation_pointer (older_gen) = r_allocation_pointer;
generation_allocation_context_start_region (older_gen) = r_allocation_start_region;
generation_allocation_segment (older_gen) = r_allocation_segment;
}
// 如果 generation_allocation_limit 等于 heap_segment_plan_allocated
// 设置 heap_segment_plan_allocated 等于 generation_allocation_pointer
// 设置 generation_allocation_limit 等于 generation_allocation_pointer
// 否则
// 在alloc_ptr到limit的空间创建一个free object, 不加入free list
if ((condemned_gen_number < max_generation))
{
// Fix the allocation area of the older generation
fix_older_allocation_area (older_gen);
}
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
if (ShouldTrackMovementForProfilerOrEtw())
{
record_survived_for_profiler(condemned_gen_number, first_condemned_address);
}
#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
// 把不使用的空间变为free object并存到free list
gen0_big_free_spaces = 0;
make_free_lists (condemned_gen_number);
// 恢复在saved_pre_plug和saved_post_plug保存的原始数据
recover_saved_pinned_info();
// 因为析构队列中的对象分代储存,这里根据升代或者降代移动析构队列中的对象
#ifdef FEATURE_PREMORTEM_FINALIZATION
finalize_queue->UpdatePromotedGenerations (condemned_gen_number, TRUE);
#endif // FEATURE_PREMORTEM_FINALIZATION
// MTHTS: leave single thread for HT processing on plan_phase
#ifdef MULTIPLE_HEAPS
dprintf(3, ("Joining after end of sweep"));
gc_t_join.join(this, gc_join_adjust_handle_age_sweep);
if (gc_t_join.joined())
#endif //MULTIPLE_HEAPS
{
// 更新GCHandle表中记录的代数
GCScan::GcPromotionsGranted(condemned_gen_number,
max_generation, &sc);
// 删除空的(无存活对象的)小对象segment和修复segment链表
// 上面有详细的注释
if (condemned_gen_number >= (max_generation -1))
{
#ifdef MULTIPLE_HEAPS
for (int i = 0; i < n_heaps; i++)
{
g_heaps[i]->rearrange_heap_segments(FALSE);
}
#else
rearrange_heap_segments(FALSE);
#endif //MULTIPLE_HEAPS
}
#ifdef MULTIPLE_HEAPS
//join all threads to make sure they are synchronized
dprintf(3, ("Restarting after Promotion granted"));
gc_t_join.restart();
#endif //MULTIPLE_HEAPS
}
#ifdef _DEBUG
for (int x = 0; x <= max_generation; x++)
{
assert (generation_allocation_start (generation_of (x)));
}
#endif //_DEBUG
// 因为已经升代了,原来gen 0的对象会变为gen 1
// 清理当前gen 1在Card Table中的标记
//clear card for generation 1. generation 0 is empty
clear_card_for_addresses (
generation_allocation_start (generation_of (1)),
generation_allocation_start (generation_of (0)));
assert ((heap_segment_allocated (ephemeral_heap_segment) ==
(generation_allocation_start (youngest_generation) +
Align (min_obj_size))));
}
//verify_partial();
}
process_ephemeral_boundaries
函数的代码:
如果当前模拟的segment是ephemeral heap segment,这个函数会在模拟当前plug的压缩前调用决定计划代边界
void gc_heap::process_ephemeral_boundaries (uint8_t* x,
int& active_new_gen_number,
int& active_old_gen_number,
generation*& consing_gen,
BOOL& allocate_in_condemned)
{
retry:
// 判断是否要设置计划代边界
// 例如当前启用升代
// - active_old_gen_number是1,active_new_gen_number是2
// - 判断plug属于gen 0的时候会计划gen 1(active_new_gen_number--)的边界
// 例如当前不启用升代
// - active_old_gen_number是1,active_new_gen_number是1
// - 判断plug属于gen 0的时候会计划gen 0(active_new_gen_number--)的边界
if ((active_old_gen_number > 0) &&
(x >= generation_allocation_start (generation_of (active_old_gen_number - 1))))
{
dprintf (1, ("crossing gen%d, x is %Ix", active_old_gen_number - 1, x));
if (!pinned_plug_que_empty_p())
{
dprintf (1, ("oldest pin: %Ix(%Id)",
pinned_plug (oldest_pin()),
(x - pinned_plug (oldest_pin()))));
}
// 如果升代
// active_old_gen_number: 2 => 1 => 0
// active_new_gen_number: 2 => 2 => 1
// 如果不升代
// active_old_gen_number: 2 => 1 => 0
// active_new_gen_number: 2 => 1 => 0
if (active_old_gen_number <= (settings.promotion ? (max_generation - 1) : max_generation))
{
active_new_gen_number--;
}
active_old_gen_number--;
assert ((!settings.promotion) || (active_new_gen_number>0));
if (active_new_gen_number == (max_generation - 1))
{
// 打印和设置统计信息
#ifdef FREE_USAGE_STATS
if (settings.condemned_generation == max_generation)
{
// We need to do this before we skip the rest of the pinned plugs.
generation* gen_2 = generation_of (max_generation);
generation* gen_1 = generation_of (max_generation - 1);
size_t total_num_pinned_free_spaces_left = 0;
// We are about to allocate gen1, check to see how efficient fitting in gen2 pinned free spaces is.
for (int j = 0; j < NUM_GEN_POWER2; j++)
{
dprintf (1, ("[h%d][#%Id]2^%d: current: %Id, S: 2: %Id, 1: %Id(%Id)",
heap_number,
settings.gc_index,
(j + 10),
gen_2->gen_current_pinned_free_spaces[j],
gen_2->gen_plugs[j], gen_1->gen_plugs[j],
(gen_2->gen_plugs[j] + gen_1->gen_plugs[j])));
total_num_pinned_free_spaces_left += gen_2->gen_current_pinned_free_spaces[j];
}
float pinned_free_list_efficiency = 0;
size_t total_pinned_free_space = generation_allocated_in_pinned_free (gen_2) + generation_pinned_free_obj_space (gen_2);
if (total_pinned_free_space != 0)
{
pinned_free_list_efficiency = (float)(generation_allocated_in_pinned_free (gen_2)) / (float)total_pinned_free_space;
}
dprintf (1, ("[h%d] gen2 allocated %Id bytes with %Id bytes pinned free spaces (effi: %d%%), %Id (%Id) left",
heap_number,
generation_allocated_in_pinned_free (gen_2),
total_pinned_free_space,
(int)(pinned_free_list_efficiency * 100),
generation_pinned_free_obj_space (gen_2),
total_num_pinned_free_spaces_left));
}
#endif //FREE_USAGE_STATS
// 出队mark_stack_array中不属于ephemeral heap segment的pinned plug,不能让它们降代
//Go past all of the pinned plugs for this generation.
while (!pinned_plug_que_empty_p() &&
(!in_range_for_segment ((pinned_plug (oldest_pin())), ephemeral_heap_segment)))
{
size_t entry = deque_pinned_plug();
mark* m = pinned_plug_of (entry);
uint8_t* plug = pinned_plug (m);
size_t len = pinned_len (m);
// detect pinned block in different segment (later) than
// allocation segment, skip those until the oldest pin is in the ephemeral seg.
// adjust the allocation segment along the way (at the end it will
// be the ephemeral segment.
heap_segment* nseg = heap_segment_in_range (generation_allocation_segment (consing_gen));
PREFIX_ASSUME(nseg != NULL);
while (!((plug >= generation_allocation_pointer (consing_gen))&&
(plug < heap_segment_allocated (nseg))))
{
//adjust the end of the segment to be the end of the plug
assert (generation_allocation_pointer (consing_gen)>=
heap_segment_mem (nseg));
assert (generation_allocation_pointer (consing_gen)<=
heap_segment_committed (nseg));
heap_segment_plan_allocated (nseg) =
generation_allocation_pointer (consing_gen);
//switch allocation segment
nseg = heap_segment_next_rw (nseg);
generation_allocation_segment (consing_gen) = nseg;
//reset the allocation pointer and limits
generation_allocation_pointer (consing_gen) =
heap_segment_mem (nseg);
}
set_new_pin_info (m, generation_allocation_pointer (consing_gen));
assert(pinned_len(m) == 0 || pinned_len(m) >= Align(min_obj_size));
generation_allocation_pointer (consing_gen) = plug + len;
generation_allocation_limit (consing_gen) =
generation_allocation_pointer (consing_gen);
}
allocate_in_condemned = TRUE;
consing_gen = ensure_ephemeral_heap_segment (consing_gen);
}
// active_new_gen_number不等于gen2的时候计划它的边界
// gen2的边界不会在这里计划,而是在前面(allocate_first_generation_start)
if (active_new_gen_number != max_generation)
{
// 防止降代的时候把所有pinned plug出队
if (active_new_gen_number == (max_generation - 1))
{
maxgen_pinned_compact_before_advance = generation_pinned_allocation_compact_size (generation_of (max_generation));
if (!demote_gen1_p)
advance_pins_for_demotion (consing_gen);
}
// 根据当前的generaion_allocation_pointer(alloc_ptr)计划代边界
plan_generation_start (generation_of (active_new_gen_number), consing_gen, x);
dprintf (1, ("process eph: allocated gen%d start at %Ix",
active_new_gen_number,
generation_plan_allocation_start (generation_of (active_new_gen_number))));
// 如果队列中仍然有pinned plug
if ((demotion_low == MAX_PTR) && !pinned_plug_que_empty_p())
{
// 并且最老(最左边)的pinned plug的代数不是0的时候
uint8_t* pplug = pinned_plug (oldest_pin());
if (object_gennum (pplug) > 0)
{
// 表示从这个pinned plug和后面的pinned plug都被降代了
// 设置降代范围
demotion_low = pplug;
dprintf (3, ("process eph: dlow->%Ix", demotion_low));
}
}
assert (generation_plan_allocation_start (generation_of (active_new_gen_number)));
}
goto retry;
}
}
如果您发现该资源为电子书等存在侵权的资源或对该资源描述不正确等,可点击“私信”按钮向作者进行反馈;如作者无回复可进行平台仲裁,我们会在第一时间进行处理!
加入交流群
请使用微信扫一扫!