hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
(この関数では, ある region 内の live オブジェクト全てを 一つの Space 内にはコンパクション出来ない場合に, コンパクション先を別の Space へと切り替える分割点をどこにするか, を計算する. (See: SplitInfo)
もし, 問題となっている region が partial object (もっと前の region から始まって 現在の region まではみ出ているオブジェクト) を持たなければ, region の先頭を分割点とする.
partial object がある場合は,
partial object が始まった region まで遡って分割点を入れる.
分割点は以下のように決める.
* 問題の region が partial object を持たない場合,
その region の先頭を分割点とする.
* partial object がある場合は, partial object 分だけを現在のコンパクション先にコンパクションし,
それ以降は別の Space にコンパクションする.
(つまり, partial object の直後を分割点とする)
// Find the point at which a space can be split and, if necessary, record the
// split point.
//
// If the current src region (which overflowed the destination space) doesn't
// have a partial object, the split point is at the beginning of the current src
// region (an "easy" split, no extra bookkeeping required).
//
// If the current src region has a partial object, the split point is in the
// region where that partial object starts (call it the split_region). If
// split_region has a partial object, then the split point is just after that
// partial object (a "hard" split where we have to record the split data and
// zero the partial_obj_size field). With a "hard" split, we know that the
// partial_obj ends within split_region because the partial object that caused
// the overflow starts in split_region. If split_region doesn't have a partial
// obj, then the split is at the beginning of split_region (another "easy"
// split).
HeapWord*
ParallelCompactData::summarize_split_space(size_t src_region,
SplitInfo& split_info,
HeapWord* destination,
HeapWord* target_end,
HeapWord** target_next)
{
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
assert(destination <= target_end, "sanity");
assert(destination + _region_data[src_region].data_size() > target_end,
"region should not fit into target space");
assert(is_region_aligned(target_end), "sanity");
{- -------------------------------------------
(1) まず, 分割点の箇所を計算する.
(以下の split_region 変数は, 分割点を入れる region を示す.
また, partial_obj_size 変数は, split_region 内の分割点の位置(先頭からのオフセット)を示す.
通常は, 引数で渡された src_region が split_region になり, 分割点は以下のように決まる.
* src_region が partial object (もっと前の region から始まって
現在の region まではみ出ているオブジェクト) を持たない場合,
src_region の先頭を分割点とする.
* partial object がある場合は, partial object 分だけを現在のコンパクション先にコンパクションし,
それ以降は別の Space にコンパクションする.
(つまり, partial object の直後を分割点とする)
ただし, コンパクション先に partial object を入れる空き領域さえない場合は,
問題の partial object が始まった region まで遡って分割点を入れる.
この場合, split_region は partial object が始まった region になる.
そして, 分割点は以下のように決まる.
* 問題の region が partial object を持たない場合,
その region の先頭を分割点とする.
* partial object がある場合は, partial object 分だけを現在のコンパクション先にコンパクションし,
それ以降は別の Space にコンパクションする.
(つまり, partial object の直後を分割点とする)
なおこの場合は, 分割点以降の範囲については, 既にコンパクション先が決まっていたのに
コンパクション先を別の領域へと変更することになるので,
対応するコンパクション先の ParallelCompactData::RegionData オブジェクト全てに対して
ParallelCompactData::RegionData::set_source_region() で
コンパクション元情報を 0 にリセットしておく.
(ついでに(トレース出力)も行う))
---------------------------------------- -}
size_t split_region = src_region;
HeapWord* split_destination = destination;
size_t partial_obj_size = _region_data[src_region].partial_obj_size();
if (destination + partial_obj_size > target_end) {
// The split point is just after the partial object (if any) in the
// src_region that contains the start of the object that overflowed the
// destination space.
//
// Find the start of the "overflow" object and set split_region to the
// region containing it.
HeapWord* const overflow_obj = _region_data[src_region].partial_obj_addr();
split_region = addr_to_region_idx(overflow_obj);
// Clear the source_region field of all destination regions whose first word
// came from data after the split point (a non-null source_region field
// implies a region must be filled).
//
// An alternative to the simple loop below: clear during post_compact(),
// which uses memcpy instead of individual stores, and is easy to
// parallelize. (The downside is that it clears the entire RegionData
// object as opposed to just one field.)
//
// post_compact() would have to clear the summary data up to the highest
// address that was written during the summary phase, which would be
//
// max(top, max(new_top, clear_top))
//
// where clear_top is a new field in SpaceInfo. Would have to set clear_top
// to target_end.
const RegionData* const sr = region(split_region);
const size_t beg_idx =
addr_to_region_idx(region_align_up(sr->destination() +
sr->partial_obj_size()));
const size_t end_idx = addr_to_region_idx(target_end);
if (TraceParallelOldGCSummaryPhase) {
gclog_or_tty->print_cr("split: clearing source_region field in ["
SIZE_FORMAT ", " SIZE_FORMAT ")",
beg_idx, end_idx);
}
for (size_t idx = beg_idx; idx < end_idx; ++idx) {
_region_data[idx].set_source_region(0);
}
// Set split_destination and partial_obj_size to reflect the split region.
split_destination = sr->destination();
partial_obj_size = sr->partial_obj_size();
}
{- -------------------------------------------
(1) もし, 分割点を入れる region に partial object がある場合は,
ParallelCompactData::RegionData::set_partial_obj_size() で
partial object 量情報を 0 にリセットする代わりに,
SplitInfo::record() で partial object の直後のアドレスを記録しておく.
---------------------------------------- -}
// The split is recorded only if a partial object extends onto the region.
if (partial_obj_size != 0) {
_region_data[split_region].set_partial_obj_size(0);
split_info.record(split_region, partial_obj_size, split_destination);
}
{- -------------------------------------------
(1) 引数で渡された target_next に, コンパクション先の領域に関する
コンパクション後の使用量情報(新しい top 位置のアドレス)を記録しておく.
---------------------------------------- -}
// Setup the continuation addresses.
*target_next = split_destination + partial_obj_size;
{- -------------------------------------------
(1) (変数宣言など)
(source_next が, 実際の分割点のアドレス)
---------------------------------------- -}
HeapWord* const source_next = region_to_addr(split_region) + partial_obj_size;
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (TraceParallelOldGCSummaryPhase) {
const char * split_type = partial_obj_size == 0 ? "easy" : "hard";
gclog_or_tty->print_cr("%s split: src=" PTR_FORMAT " src_c=" SIZE_FORMAT
" pos=" SIZE_FORMAT,
split_type, source_next, split_region,
partial_obj_size);
gclog_or_tty->print_cr("%s split: dst=" PTR_FORMAT " dst_c=" SIZE_FORMAT
" tn=" PTR_FORMAT,
split_type, split_destination,
addr_to_region_idx(split_destination),
*target_next);
if (partial_obj_size != 0) {
HeapWord* const po_beg = split_info.destination();
HeapWord* const po_end = po_beg + split_info.partial_obj_size();
gclog_or_tty->print_cr("%s split: "
"po_beg=" PTR_FORMAT " " SIZE_FORMAT " "
"po_end=" PTR_FORMAT " " SIZE_FORMAT,
split_type,
po_beg, addr_to_region_idx(po_beg),
po_end, addr_to_region_idx(po_end));
}
}
{- -------------------------------------------
(1) 分割点のアドレス(source_next)をリターン
---------------------------------------- -}
return source_next;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.