Top


定義場所(file name)

hotspot/src/share/vm/services/memoryManager.cpp

名前(function name)

instanceOop MemoryManager::get_memory_manager_instance(TRAPS) {

本体部(body)

    (この関数では, 最初に呼ばれた際に 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.