hotspot/src/share/vm/memory/threadLocalAllocBuffer.cpp
void ThreadLocalAllocBuffer::accumulate_statistics() {
{- -------------------------------------------
(1) まず, _allocation_fraction を更新するのに十分なだけの情報が
溜まっているかどうかを判断しておく (以下の update_allocation_history).
「TLAB として利用されうる最大長」に対して「実際に TLAB として使用されている量」が小さすぎる場合には,
十分ではないと判断する.
なお, 具体的には以下のように計算.
* 統計情報の更新に十分なだけの情報が溜まっているか (以下の update_allocation_history).
「実際に TLAB として使用されている量」が「TLAB として利用されうる最大長」の半分以上であれば, 溜まっていると判断.
* TLAB として利用されうる最大長 (以下の capacity)
CollectedHeap::tlab_capacity() で, 現在のヒープで TLAB として利用されうる最大長を取得
(この数値は典型的には Eden 領域長).
* TLAB として利用可能な残り容量 (以下の unused)
CollectedHeap::unsafe_max_tlab_alloc() で,
現在のヒープから (GC やヒープ拡張などを起こさずに) 確保可能な最大の TLAB 長を取得
(この数値は典型的には Eden 領域の残り容量).
* 実際に TLAB として使用されている量 (以下の used)
「capacity - unused」 で推定量を出す.
---------------------------------------- -}
size_t capacity = Universe::heap()->tlab_capacity(myThread()) / HeapWordSize;
size_t unused = Universe::heap()->unsafe_max_tlab_alloc(myThread()) / HeapWordSize;
size_t used = capacity - unused;
// Update allocation history if a reasonable amount of eden was allocated.
bool update_allocation_history = used > 0.5 * capacity;
{- -------------------------------------------
(1) _gc_waste フィールドの値を, 現在の TLAB の残容量分だけ増加させておく.
---------------------------------------- -}
_gc_waste += (unsigned)remaining();
{- -------------------------------------------
(1) (トレース出力)
---------------------------------------- -}
if (PrintTLAB && (_number_of_refills > 0 || Verbose)) {
print_stats("gc");
}
{- -------------------------------------------
(1) 前回の ThreadLocalAllocBuffer::accumulate_statistics() 以降で
この TLAB が1回以上新しく確保され直している場合には,
この TLAB の情報を global_stats の統計情報に加算しておく.
(TLAB の確保が1回以上実行されたかどうかは, _number_of_refills フィールドの値で判断している.
_number_of_refills フィールドは,
ThreadLocalAllocBuffer::initialize_statistics() で 0 に初期化された後
新しい TLAB の確保が行われるたびに ThreadLocalAllocBuffer::fill() でインクリメントされるため,
これが 0 でなければ新しい TLAB の確保があったことになる.
See: ThreadLocalAllocBuffer::fill())
また, _allocation_fraction を更新するのに十分なだけの情報が溜まっていると判断した場合は,
Eden 内で確保された量のうちでこの TLAB (= このスレッド) が確保した量の割合(以下の alloc_frac)を計算し,
_allocation_fraction の値を更新しておく.
---------------------------------------- -}
if (_number_of_refills > 0) {
if (update_allocation_history) {
// Average the fraction of eden allocated in a tlab by this
// thread for use in the next resize operation.
// _gc_waste is not subtracted because it's included in
// "used".
size_t allocation = _number_of_refills * desired_size();
double alloc_frac = allocation / (double) used;
_allocation_fraction.sample(alloc_frac);
}
global_stats()->update_allocating_threads();
global_stats()->update_number_of_refills(_number_of_refills);
global_stats()->update_allocation(_number_of_refills * desired_size());
global_stats()->update_gc_waste(_gc_waste);
global_stats()->update_slow_refill_waste(_slow_refill_waste);
global_stats()->update_fast_refill_waste(_fast_refill_waste);
} else {
assert(_number_of_refills == 0 && _fast_refill_waste == 0 &&
_slow_refill_waste == 0 && _gc_waste == 0,
"tlab stats == 0");
}
{- -------------------------------------------
(1) この TLAB の _slow_allocations 情報を global_stats の統計情報に加算しておく.
(なお, _slow_allocations フィールドは TLAB を使わずに直接確保された回数が何回あったかを示す値.
ThreadLocalAllocBuffer::initialize_statistics() で 0 に初期化された後
TLAB を用いない slow-path での確保が行われる度に
ThreadLocalAllocBuffer::record_slow_allocation() でインクリメントされる.
See: ThreadLocalAllocBuffer::record_slow_allocation())
---------------------------------------- -}
global_stats()->update_slow_allocations(_slow_allocations);
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.