hotspot/src/share/vm/runtime/virtualspace.cpp
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
char* requested_address,
const size_t noaccess_prefix,
bool executable) {
{- -------------------------------------------
(1) (なお, 引数の noaccess_prefix は,
UseCompressedOop 時に Null Check を暗黙的に行うために
ヒープの先頭にアクセス禁止のメモリプロテクションを張る場合のプロテクション領域の大きさを示す.
プロテクションが不要なら 0.
See: ReservedSpace::protect_noaccess_prefix())
---------------------------------------- -}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
const size_t granularity = os::vm_allocation_granularity();
assert((size & granularity - 1) == 0,
"size not aligned to os::vm_allocation_granularity()");
assert((alignment & granularity - 1) == 0,
"alignment not aligned to os::vm_allocation_granularity()");
assert(alignment == 0 || is_power_of_2((intptr_t)alignment),
"not a power of 2");
{- -------------------------------------------
(1) フィールドの初期化
(まだメモリ領域が確保できていないのでいくつかのフィールドの値は適当.
領域の reserve 後に正式な値を入れる)
---------------------------------------- -}
_base = NULL;
_size = 0;
_special = false;
_executable = executable;
_alignment = 0;
_noaccess_prefix = 0;
{- -------------------------------------------
(1) 引数で渡された size が 0 なら, ここでリターン
---------------------------------------- -}
if (size == 0) {
return;
}
{- -------------------------------------------
(1) (変数宣言など)
---------------------------------------- -}
// If OS doesn't support demand paging for large page memory, we need
// to use reserve_memory_special() to reserve and pin the entire region.
bool special = large && !os::can_commit_large_page_memory();
char* base = NULL;
{- -------------------------------------------
(1) もし確保するアドレスが指定されている場合には(= requested_address が 0 でなければ),
そのアドレスを noaccess_prefix 分だけ調整しておく.
---------------------------------------- -}
if (requested_address != 0) {
requested_address -= noaccess_prefix; // adjust requested address
assert(requested_address != NULL, "huge noaccess prefix?");
}
{- -------------------------------------------
(1) 以下の special の条件は,
引数で Large Page を使用することが指定されているが (= large が true),
OS の制約により large page については reserve と commit は同時に行わなくてはいけない場合
(= os::can_commit_large_page_memory() が false).
この場合, os::reserve_memory_special() で確保を試みる.
確保が失敗したら, 以下の通常の確保処理にフォールバックする.
確保が成功しても, 指定のアドレスに確保できていなければ, 確保は失敗したことにしてここでリターンする.
---------------------------------------- -}
if (special) {
base = os::reserve_memory_special(size, requested_address, executable);
if (base != NULL) {
{- -------------------------------------------
(1.1) 確保が成功したが, 指定のアドレスに確保できていないケース (ここでリターン)
---------------------------------------- -}
if (failed_to_reserve_as_requested(base, requested_address, size, true)) {
// OS ignored requested address. Try different address.
return;
}
{- -------------------------------------------
(1.1) 確保が成功したケース (このまま下の処理へとフォールスルー)
---------------------------------------- -}
// Check alignment constraints
if (alignment > 0) {
assert((uintptr_t) base % alignment == 0,
"Large pages returned a non-aligned address");
}
_special = true;
{- -------------------------------------------
(1.1) 確保が失敗したケース (このまま下の処理へとフォールスルー)
---------------------------------------- -}
} else {
// failed; try to reserve regular memory below
if (UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) ||
!FLAG_IS_DEFAULT(LargePageSizeInBytes))) {
if (PrintCompressedOopsMode) {
tty->cr();
tty->print_cr("Reserve regular memory without large pages.");
}
}
}
}
{- -------------------------------------------
(1) (以下は, 上述の special の条件が成り立っていない場合か, special は true だったが確保に失敗した場合の処理)
---------------------------------------- -}
if (base == NULL) {
{- -------------------------------------------
(1) (OS が 64K 位で align された領域を返してくれると想定している, とのこと.
返してくれなかった場合は, (後で述べるように)アラインするために確保し直す処理が行われる.)
---------------------------------------- -}
// Optimistically assume that the OSes returns an aligned base pointer.
// When reserving a large address range, most OSes seem to align to at
// least 64K.
{- -------------------------------------------
(1) メモリ領域の reserve を試みる.
確保するアドレスが指定されているかどうかで確保処理が少し異なる.
* 確保するアドレスが指定されている場合には(= requested_address が 0 でなければ),
os::attempt_reserve_memory_at() で確保を試みる.
もし指定のアドレスに確保できていなければ (= failed_to_reserve_as_requested() が true),
reserve は失敗しているので, ここでリターンする.
* 確保するアドレスが指定されていなければ(= requested_address が 0 ならば),
os::reserve_memory() で確保を試みる.
reserve が失敗していれば (= base が NULL), ここでリターン
---------------------------------------- -}
// If the memory was requested at a particular address, use
// os::attempt_reserve_memory_at() to avoid over mapping something
// important. If available space is not detected, return NULL.
if (requested_address != 0) {
base = os::attempt_reserve_memory_at(size, requested_address);
if (failed_to_reserve_as_requested(base, requested_address, size, false)) {
// OS ignored requested address. Try different address.
base = NULL;
}
} else {
base = os::reserve_memory(size, NULL, alignment);
}
if (base == NULL) return;
{- -------------------------------------------
(1) 確保した領域のアラインメントが正しいかどうかを確認する.
(確保した領域の先頭アドレス (base) が alignment でアラインされているか, を確認)
もしアラインされていなければ, 確保した領域は os::release_memory() でいったん解放し,
以下のようにして条件に合うメモリ領域が確保できるまで繰り返す.
(1) alignment 分大きいサイズで os::reserve_memory() し直す.
(alignment 分大きくすれば, アライン条件に合うアドレスが必ず取れる)
(なおこの os::reserve_memory() が失敗したら, 確保は失敗ということにしてここでリターン)
(2) reserve できた領域内で条件に合うアドレスを探し,
確保できた領域はいったん os::release_memory() した後,
改めて, そのアドレスから size 分の領域を os::release_memory() で確保する.
(この os::release_memory() が成功するまでループ)
---------------------------------------- -}
// Check alignment constraints
if (alignment > 0 && ((size_t)base & alignment - 1) != 0) {
// Base not aligned, retry
if (!os::release_memory(base, size)) fatal("os::release_memory failed");
// Reserve size large enough to do manual alignment and
// increase size to a multiple of the desired alignment
size = align_size_up(size, alignment);
size_t extra_size = size + alignment;
do {
char* extra_base = os::reserve_memory(extra_size, NULL, alignment);
if (extra_base == NULL) return;
// Do manual alignement
base = (char*) align_size_up((uintptr_t) extra_base, alignment);
assert(base >= extra_base, "just checking");
// Re-reserve the region at the aligned base address.
os::release_memory(extra_base, extra_size);
base = os::reserve_memory(size, base);
} while (base == NULL);
}
}
// Done
{- -------------------------------------------
(1) フィールドの初期化 (メモリ領域が確保できたので, 正式な値で初期化)
---------------------------------------- -}
_base = base;
_size = size;
_alignment = MAX2(alignment, (size_t) os::vm_page_size());
_noaccess_prefix = noaccess_prefix;
{- -------------------------------------------
(1) (assert)
---------------------------------------- -}
// Assert that if noaccess_prefix is used, it is the same as alignment.
assert(noaccess_prefix == 0 ||
noaccess_prefix == _alignment, "noaccess prefix wrong");
assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
"area must be distinguisable from marks for mark-sweep");
assert(markOopDesc::encode_pointer_as_mark(&_base[size])->decode_pointer() == &_base[size],
"area must be distinguisable from marks for mark-sweep");
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.