メモリ確保の試みが全て失敗した場合, 最終的に CollectedHeap::mem_allocate() が呼び出される (See: here for details). ParallelScavengeHeap は CollectedHeap::mem_allocate() をオーバーライドしているので, 実際に呼び出されるのは ParallelScavengeHeap::mem_allocate() になる.
ParallelScavengeHeap::mem_allocate() 内では GC を実行してでも確保が試みられる. なお, ParallelScavengeHeap::mem_allocate() には2種類の allocation policy が存在している (basic allocation policy, failed allocation policy). これは, VM Operation が重い処理なので, 可能な限り VM Operation の回数を減らすための工夫である.
basic allocation policy は, safepoint 停止を必要としない手順は全て使用して確保を試みる. (lock を取ってもいいし, heap を expand してもいい)
failed allocation policy では, basic allocation policy では確保できなかった際に, safepoint 停止させて行われる. GC やヒープの拡張を行い, どうしてもダメなら OutOfMemory 処理などを行う. (なお, failed allocation policy は VM Thread から呼び出される)
なお, 複数のスレッドが failed allocation policy に来た場合にも, VM Thread によって実際に実行される VM Operation は1回だけになる.
    ((cite: hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp))
    // There are two levels of allocation policy here.
    //
    // When an allocation request fails, the requesting thread must invoke a VM
    // operation, transfer control to the VM thread, and await the results of a
    // garbage collection. That is quite expensive, and we should avoid doing it
    // multiple times if possible.
    //
    // To accomplish this, we have a basic allocation policy, and also a
    // failed allocation policy.
    //
    // The basic allocation policy controls how you allocate memory without
    // attempting garbage collection. It is okay to grab locks and
    // expand the heap, if that can be done without coming to a safepoint.
    // It is likely that the basic allocation policy will not be very
    // aggressive.
    //
    // The failed allocation policy is invoked from the VM thread after
    // the basic allocation policy is unable to satisfy a mem_allocate
    // request. This policy needs to cover the entire range of collection,
    // heap expansion, and out-of-memory conditions. It should make every
    // attempt to allocate the requested memory.
    // Basic allocation policy. Should never be called at a safepoint, or
    // from the VM thread.
    //
    // This method must handle cases where many mem_allocate requests fail
    // simultaneously. When that happens, only one VM operation will succeed,
    // and the rest will not be executed. For that reason, this method loops
    // during failed allocation attempts. If the java heap becomes exhausted,
    // we rely on the size_policy object to force a bail out.
ParallelScavengeHeap::mem_allocate() の処理の流れは GenCollectorPolicy::mem_allocate_work() に似ている.
ParallelScavengeHeap::mem_allocate()
-> (1) まず PSYoungGen::allocate() で確保を試みる. (この確保が成功すれば以下の処理は行わない)
       -> PSYoungGen::allocate()
          -> (See: here for details)
   (2) 確保に成功するまで以下の処理を繰り返す.
       (メモリ確保に成功するか, あるいは成功しないと判断するまでループ)
       -> (1) Heap_lock を取った状態で PSYoungGen::allocate() 及び PSOldGen::allocate() による確保処理を行う
              -> PSYoungGen::allocate()
                 -> (See: here for details)
              -> PSOldGen::allocate()  (<= Young Gen にいれるには大きすぎる確保要求の場合)
                 -> PSOldGen::allocate_noexpand()
                 -> PSOldGen::expand_and_allocate()
    
          (2) まだ確保できていなければ, GC を実行してから確保を試みる.
              -> VM_ParallelGCFailedAllocation::doit()
                 -> ParallelScavengeHeap::failed_mem_allocate()
    
                    -> (1) まず PSScavenge::invoke() で Minor GC を行い, その後 Young Generation から確保してみる.
                           -> PSScavenge::invoke()
                              -> (See: here for details)
                           -> PSYoungGen::allocate()
                              -> (See: here for details)
       
                       (2) 確保に失敗したら, ParallelScavengeHeap::invoke_full_gc() で簡単に Full GC を行った後, もう一度 Young Generation からの確保を試みる.
                           -> ParallelScavengeHeap::invoke_full_gc()
                              (UseParallelOldGC オプションに応じて, 以下のどちらかを呼び出す)
                              -> PSParallelCompact::invoke()
                                 -> (See: here for details)
                              -> PSMarkSweep::invoke()
                                 -> (See: here for details)
                           -> PSYoungGen::allocate()
                              -> (See: here for details)
       
                       (3) まだ確保が成功していなければ, Old Generation から確保してみる.
                           -> PSOldGen::allocate()
                              -> (同上)
       
                       (4) まだ確保が成功していなければ, invoke_full_gc() で(今度は完璧に) Full GC を行い, その後 Young Generation からの確保を試みる.
                           -> ParallelScavengeHeap::invoke_full_gc()
                              -> (同上)
                           -> PSYoungGen::allocate()
                              -> (See: here for details)
       
                       (5) それでもまだ確保が成功していなければ, もう一度 Old Generation から確保を試みる.
                           (今度は完璧に Full GC した後なので, さっきとは結果が変わる可能性がある)
                           -> PSOldGen::allocate()
                              -> (同上)
          (3) GC 時間が制限を越えていれば NULL をリターン. そうでなければ, 確保が成功するまでループを繰り返す.
See: here for details
See: here for details
(#Under Construction)
(#Under Construction)
See: here for details
See: here for details
See: here for details
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.