hotspot/src/share/vm/services/memoryManager.cpp
instanceOop MemoryManager::get_memory_manager_instance(TRAPS) {
(この関数では, 最初に呼ばれた際に MemoryManager インスタンスを生成し,
二回目以降は最初に作ったインスタンスを流用する模様.
See: MemoryPool::get_memory_pool_instance())
{- -------------------------------------------
(1) 並行して, 他のスレッドがインスタンスを作り
_memory_mgr_obj フィールドの書き換えを行っているかもしれないので,
_memory_mgr_obj フィールドの読み取りは OrderAccess::load_ptr_acquire() で行う.
(_memory_mgr_obj フィールドのポインタだけは見えたが,
ポインタの指示先の同期は取られてなかった, という事態を防ぐ)
---------------------------------------- -}
// Must do an acquire so as to force ordering of subsequent
// loads from anything _memory_mgr_obj points to or implies.
instanceOop mgr_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_mgr_obj);
{- -------------------------------------------
(1) _memory_mgr_obj フィールドがまだ NULL の場合のみ, 以下の if 文中で新しいインスタンスを生成する.
(一度インスタンスを作って _memory_mgr_obj フィールドにキャッシュ済みの場合には, 新しく作ることはしない)
---------------------------------------- -}
if (mgr_obj == NULL) {
{- -------------------------------------------
(1) sun.management.ManagementFactory.createGarbageCollector() もしくは
sun.management.ManagementFactory.createMemoryManager() を呼び出して
新しい sun.management.MemoryPoolImpl (もしくは sun.management.GarbageCollectorImpl) オブジェクトを生成する.
(なお, このインスタンス生成処理はロックで保護していないが, 複数のスレッドが実行してしまっても問題ない.
余分に作ってしまっても GC で消えるだけなので)
---------------------------------------- -}
// It's ok for more than one thread to execute the code up to the locked region.
// Extra manager instances will just be gc'ed.
klassOop k = Management::sun_management_ManagementFactory_klass(CHECK_0);
instanceKlassHandle ik(THREAD, k);
Handle mgr_name = java_lang_String::create_from_str(name(), CHECK_0);
JavaValue result(T_OBJECT);
JavaCallArguments args;
args.push_oop(mgr_name); // Argument 1
Symbol* method_name = NULL;
Symbol* signature = NULL;
if (is_gc_memory_manager()) {
method_name = vmSymbols::createGarbageCollector_name();
signature = vmSymbols::createGarbageCollector_signature();
args.push_oop(Handle()); // Argument 2 (for future extension)
} else {
method_name = vmSymbols::createMemoryManager_name();
signature = vmSymbols::createMemoryManager_signature();
}
JavaCalls::call_static(&result,
ik,
method_name,
signature,
&args,
CHECK_0);
instanceOop m = (instanceOop) result.get_jobject();
instanceHandle mgr(THREAD, m);
{- -------------------------------------------
(1) _memory_mgr_obj フィールドに作ったオブジェクトを格納する.
この処理は Management_lock のロックを取って排他的に行う.
なお, ここまでの処理の間に, 他のスレッドが _memory_mgr_obj フィールドを書き換えているかもしれないので,
ロックの取得後に, もう一度 _memory_mgr_obj フィールドを確認する.
(Management_lock のロック処理で acquire を取っているので,
確認のためのロード処理がこれより上にリオーダされることはないが,
確認結果が NULL でなければそれを返値としてリターンするので
確認自体もやっぱり OrderAccess::load_ptr_acquire() で行う.
(返値を受け取った側で, ポインタだけは見えたが指示先の同期は取られてなかった, ということになりかねないので))
実際の _memory_mgr_obj フィールドの書き換えは,
(上の OrderAccess::load_ptr_acquire() で見えるように) OrderAccess::release_store_ptr() で行う.
---------------------------------------- -}
{
// Get lock before setting _memory_mgr_obj
// since another thread may have created the instance
MutexLocker ml(Management_lock);
// Check if another thread has created the management object. We reload
// _memory_mgr_obj here because some other thread may have initialized
// it while we were executing the code before the lock.
//
// The lock has done an acquire, so the load can't float above it, but
// we need to do a load_acquire as above.
mgr_obj = (instanceOop)OrderAccess::load_ptr_acquire(&_memory_mgr_obj);
if (mgr_obj != NULL) {
return mgr_obj;
}
// Get the address of the object we created via call_special.
mgr_obj = mgr();
// Use store barrier to make sure the memory accesses associated
// with creating the management object are visible before publishing
// its address. The unlock will publish the store to _memory_mgr_obj
// because it does a release first.
OrderAccess::release_store_ptr(&_memory_mgr_obj, mgr_obj);
}
}
{- -------------------------------------------
(1) 結果をリターン
---------------------------------------- -}
return mgr_obj;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.