HeapWord* TwoGenerationCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_large_noref, bool is_tlab, bool* notify_ref_lock) { GenCollectedHeap *gch = GenCollectedHeap::heap(); GCCauseSetter x(gch, GCCause::_allocation_failure); HeapWord* result = NULL; // The gc_prologues have not executed yet. The value // for incremental_collection_will_fail() is the remanent // of the last collection. if (!gch->incremental_collection_will_fail()) { // Do an incremental collection. gch->do_collection(false /* full */, false /* clear_all_soft_refs */, size /* size */, is_large_noref /* is_large_noref */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */, notify_ref_lock /* notify_ref_lock */); } else { // The incremental_collection_will_fail flag is set if the // next incremental collection will not succeed (e.g., the // DefNewGeneration didn't think it had space to promote all // its objects). However, that last incremental collection // continued, allowing all older generations to collect (and // perhaps change the state of the flag). // // If we reach here, we know that an incremental collection of // all generations left us in the state where incremental collections // will fail, so we just try allocating the requested space. // If the allocation fails everywhere, force a full collection. // We're probably very close to being out of memory, so forcing many // collections now probably won't help. if (PrintGC && Verbose) { gclog_or_tty->print_cr("TwoGenerationCollectorPolicy::satisfy_failed_allocation:" " attempting allocation anywhere before full collection"); } result = gch->attempt_allocation(size, is_large_noref, is_tlab, false /* first_only */); if (result != NULL) { assert(gch->is_in(result), "result not in heap"); return result; } // Allocation request hasn't yet been met; try a full collection. gch->do_collection(true /* full */, false /* clear_all_soft_refs */, size /* size */, is_large_noref /* is_large_noref */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */, notify_ref_lock /* notify_ref_lock */); } result = gch->attempt_allocation(size, is_large_noref, is_tlab, false /*first_only*/); if (result != NULL) { assert(gch->is_in(result), "result not in heap"); return result; } // OK, collection failed, try expansion. for (int i = number_of_generations() - 1 ; i>= 0; i--) { Generation *gen = gch->get_gen(i); if (gen->should_allocate(size, is_large_noref, is_tlab)) { result = gen->expand_and_allocate(size, is_large_noref, is_tlab); if (result != NULL) { assert(gch->is_in(result), "result not in heap"); return result; } } } // If we reach this point, we're really out of memory. Try every trick // we can to reclaim memory. Force collection of soft references. Force // a complete compaction of the heap. Any additional methods for finding // free memory should be here, especially if they are expensive. If this // attempt fails, an OOM exception will be thrown. { IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted gch->do_collection(true /* full */, true /* clear_all_soft_refs */, size /* size */, is_large_noref /* is_large_noref */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */, notify_ref_lock /* notify_ref_lock */); } result = gch->attempt_allocation(size, is_large_noref, is_tlab, false /* first_only */); if (result != NULL) { assert(gch->is_in(result), "result not in heap"); return result; } // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be // appropriate. return NULL; }
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) { GenCollectedHeap *gch = GenCollectedHeap::heap(); GCCauseSetter x(gch, GCCause::_allocation_failure); HeapWord* result = NULL; assert(size != 0, "Precondition violated"); if (GC_locker::is_active_and_needs_gc()) { // GC locker is active; instead of a collection we will attempt // to expand the heap, if there's room for expansion. if (!gch->is_maximal_no_gc()) { result = expand_heap_and_allocate(size, is_tlab); } return result; // could be null if we are out of space } else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) { // Do an incremental collection. gch->do_collection(false /* full */, false /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } else { if (Verbose && PrintGCDetails) { gclog_or_tty->print(" :: Trying full because partial may fail :: "); } // Try a full collection; see delta for bug id 6266275 // for the original code and why this has been simplified // with from-space allocation criteria modified and // such allocation moved out of the safepoint path. gch->do_collection(true /* full */, false /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } result = gch->attempt_allocation(size, is_tlab, false /*first_only*/); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } // OK, collection failed, try expansion. result = expand_heap_and_allocate(size, is_tlab); if (result != NULL) { return result; } // If we reach this point, we're really out of memory. Try every trick // we can to reclaim memory. Force collection of soft references. Force // a complete compaction of the heap. Any additional methods for finding // free memory should be here, especially if they are expensive. If this // attempt fails, an OOM exception will be thrown. { UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted gch->do_collection(true /* full */, true /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } result = gch->attempt_allocation(size, is_tlab, false /* first_only */); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } assert(!should_clear_all_soft_refs(), "Flag should have been handled and cleared prior to this point"); // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be // appropriate. return NULL; }
/** * 处理上层应用线程(Java级线程)的一次内存申请失败 * 1. Gc类型选择 * 1).如果Gc操作已被触发但还无法被执行,则放弃本次Gc操作 * 2).如果执行增量式安全,则执行一次MinorGc * 3).只能执行一次Full Gc * 2. 从年青代-老年代依次尝试分配内存块 * 3. 从老年代-年青代依次扩展内存容量尝试分配内存块 * 4. 执行一次彻底的Full Gc(清理所有的软引用) * 5. 从年青代-老年代依次尝试分配内存块 */ HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size, bool is_tlab) { GenCollectedHeap *gch = GenCollectedHeap::heap(); GCCauseSetter x(gch, GCCause::_allocation_failure); HeapWord* result = NULL; assert(size != 0, "Precondition violated"); if (GC_locker::is_active_and_needs_gc()) { //Gc操作已被触发但还无法被执行 if (!gch->is_maximal_no_gc()) { // 当前有内存代允许扩展内存容量,则试图通过扩展内存代的容量来分配内存块 result = expand_heap_and_allocate(size, is_tlab); } return result; // could be null if we are out of space } else if (!gch->incremental_collection_will_fail(false /* don't consult_young */)) { //如果当前增量式可行,则只触发一个Minor Gc //增量式GC gch->do_collection(false /* full */, false /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } else { //执行一次Full Gc if (Verbose && PrintGCDetails) { gclog_or_tty->print(" :: Trying full because partial may fail :: "); } // Try a full collection; see delta for bug id 6266275 // for the original code and why this has been simplified // with from-space allocation criteria modified and // such allocation moved out of the safepoint path. gch->do_collection(true /* full */, false /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } //执行一次Gc之后,再次从内存堆的各个内存代中依次分配指定大小的内存块 result = gch->attempt_allocation(size, is_tlab, false /*first_only*/); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } //执行一次Gc之后可能有剩余的空间来扩展各内存代的容量, //所以再次尝试通过允许扩展内存代容量的方式来试图分配指定大小的内存块 result = expand_heap_and_allocate(size, is_tlab); if (result != NULL) { return result; } // If we reach this point, we're really out of memory. Try every trick // we can to reclaim memory. Force collection of soft references. Force // a complete compaction of the heap. Any additional methods for finding // free memory should be here, especially if they are expensive. If this // attempt fails, an OOM exception will be thrown. { IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted //最后再进行一次彻底的Gc: 回收所有的内存代+清除软引用 gch->do_collection(true /* full */, true /* clear_all_soft_refs */, size /* size */, is_tlab /* is_tlab */, number_of_generations() - 1 /* max_level */); } //经过一次彻底的Gc之后,最后一次尝试依次从各内存代分配指定大小的内存块 result = gch->attempt_allocation(size, is_tlab, false /* first_only */); if (result != NULL) { assert(gch->is_in_reserved(result), "result not in heap"); return result; } assert(!should_clear_all_soft_refs(), "Flag should have been handled and cleared prior to this point"); // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be // appropriate. return NULL; }