hotspot/src/share/vm/memory/space.hpp
#define SCAN_AND_COMPACT(obj_size) { \
{- -------------------------------------------
(1) (この関数では, bottom() から _end_of_live (これは phase2 中に値を設定) までの領域に対して
オブジェクトの移動処理を行う.
なお, この処理では LiveRange オブジェクトが使用されている (See: LiveRange))
---------------------------------------- -}
/* Copy all live objects to their new location \
* Used by MarkSweep::mark_sweep_phase4() */ \
\
{- -------------------------------------------
(1) (変数宣言など)
(q は現在処理しているオブジェクトを指すポインタ.
t は処理範囲の終端を示すポインタ.)
---------------------------------------- -}
HeapWord* q = bottom(); \
HeapWord* const t = _end_of_live; \
debug_only(HeapWord* prev_q = NULL); \
\
{- -------------------------------------------
(1) (領域の先頭部分には, コンパクションで場所が移動しないオブジェクトの塊が存在していることがある.
(領域の先頭のオブジェクトが is_gc_marked() で false を返すにも関わらず,
_first_dead の指し先がもっと先になっている場合には,
こういう塊が存在しているケース)
(See: CompactibleSpace::forward())
これらのオブジェクトは, 場所が移動しないので, phase4 で行うべき処理はない.
そこで, そういった塊が存在する場合には,
以下の if ブロック内でその部分をスキップする.)
---------------------------------------- -}
if (q < t && _first_dead > q && \
!oop(q)->is_gc_marked()) { \
debug_only( \
/* we have a chunk of the space which hasn't moved and we've reinitialized \
* the mark word during the previous pass, so we can't use is_gc_marked for \
* the traversal. */ \
HeapWord* const end = _first_dead; \
\
while (q < end) { \
size_t size = obj_size(q); \
assert(!oop(q)->is_gc_marked(), \
"should be unmarked (special dense prefix handling)"); \
VALIDATE_MARK_SWEEP_ONLY(MarkSweep::live_oop_moved_to(q, size, q)); \
debug_only(prev_q = q); \
q += size; \
} \
) /* debug_only */ \
\
if (_first_dead == t) { \
q = t; \
} else { \
/* $$$ Funky */ \
q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \
} \
} \
\
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
const intx scan_interval = PrefetchScanIntervalInBytes; \
const intx copy_interval = PrefetchCopyIntervalInBytes; \
{- -------------------------------------------
(1) 処理範囲の終端(t)に到達するまで処理を行っていく.
この処理は以下のようにして行う.
* dead オブジェクトに到達した場合 (= is_gc_marked() が false の場合):
phase2 の処理により, そこには次の live object の場所を示す
LiveRange オブジェクトが埋まっているはずなので,
そのアドレスまでポインタ(q)を進める.
(これにより, dead オブジェクトが連続している領域を一気にスキップする)
* 処理対象の箇所(q)のオブジェクトが生きている間 (= is_gc_marked() が true の場合):
Copy::aligned_conjoint_words() でそのオブジェクトをコンパクション先にコピーし,
oopDesc::init_mark() で, そのオブジェクトの mark フィールドを初期状態の値にリセットする.
その後, そのオブジェクトの大きさ分だけポインタ(q)を前に進める.
(なお高速化のため, Prefetch::read() と Prefetch::write() で
それぞれ PrefetchScanIntervalInBytes バイト, 及び PrefetchCopyIntervalInBytes バイトずつ
メモリをプリフェッチしながら行う)
---------------------------------------- -}
while (q < t) { \
if (!oop(q)->is_gc_marked()) { \
/* mark is pointer to next marked oop */ \
debug_only(prev_q = q); \
q = (HeapWord*) oop(q)->mark()->decode_pointer(); \
assert(q > prev_q, "we should be moving forward through memory"); \
} else { \
/* prefetch beyond q */ \
Prefetch::read(q, scan_interval); \
\
/* size and destination */ \
size_t size = obj_size(q); \
HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \
\
/* prefetch beyond compaction_top */ \
Prefetch::write(compaction_top, copy_interval); \
\
/* copy object and reinit its mark */ \
VALIDATE_MARK_SWEEP_ONLY(MarkSweep::live_oop_moved_to(q, size, \
compaction_top)); \
assert(q != compaction_top, "everything in this pass should be moving"); \
Copy::aligned_conjoint_words(q, compaction_top, size); \
oop(compaction_top)->init_mark(); \
assert(oop(compaction_top)->klass() != NULL, "should have a class"); \
\
debug_only(prev_q = q); \
q += size; \
} \
} \
\
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
/* Let's remember if we were empty before we did the compaction. */ \
bool was_empty = used_region().is_empty(); \
{- -------------------------------------------
(1) オブジェクトの移動処理が終わったので,
CompactibleSpace::reset_after_compaction() を呼んで
領域の top 位置を修正しておく.
---------------------------------------- -}
/* Reset space after compaction is complete */ \
reset_after_compaction(); \
{- -------------------------------------------
(1) #TODO
---------------------------------------- -}
/* We do this clear, below, since it has overloaded meanings for some */ \
/* space subtypes. For example, OffsetTableContigSpace's that were */ \
/* compacted into will have had their offset table thresholds updated */ \
/* continuously, but those that weren't need to have their thresholds */ \
/* re-initialized. Also mangles unused area for debugging. */ \
if (used_region().is_empty()) { \
if (!was_empty) clear(SpaceDecorator::Mangle); \
} else { \
if (ZapUnusedHeapArea) mangle_unused_area(); \
} \
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.