创建一个对象引起oom在jvm内部的流程。(ParNew & CMS)
1.首先从new字节码的解释器入口找到对应的内存分配代码,具体关键代码如下:
HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
...
HeapWord* result = NULL;
...
bool gc_overhead_limit_was_exceeded = false;
// 1.尝试申请内存
result = Universe::heap()->mem_allocate(size,
&gc_overhead_limit_was_exceeded);
if (result != NULL) {
...
return result;
}
...
// 2.oom
THROW_OOP_0(Universe::out_of_memory_error_gc_overhead_limit());
}
尝试分配内存成功则返回失败则抛出OOM
2.申请内存关键代码如下:
HeapWord* GenCollectedHeap::mem_allocate(size_t size,
bool* gc_overhead_limit_was_exceeded) {
return collector_policy()->mem_allocate_work(size,
false /* is_tlab */,
gc_overhead_limit_was_exceeded);
}
HeapWord* GenCollectorPolicy::mem_allocate_work(size_t size,
bool is_tlab,
bool* gc_overhead_limit_was_exceeded) {
HeapWord* result = NULL;
// 循环直到 分配到空间活着gc后仍无法分配
for (int try_count = 1; /* return or throw */; try_count += 1) {
HandleMark hm; // discard any handles allocated in each iteration
Generation *gen0 = gch->get_gen(0);
// 1.判断是否应该分配,如大对象直接放入老年代的情况。
if (gen0->should_allocate(size, is_tlab)) {
// 2.尝试从young gen分配
result = gen0->par_allocate(size, is_tlab);
if (result != NULL) {
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
}
unsigned int gc_count_before; // read inside the Heap_lock locked region
{
...
// 3.当有一些特殊情况会允许对象分配在old gen 中
bool first_only = ! should_try_older_generation_allocation(size);
// 4.尝试分配
result = gch->attempt_allocation(size, is_tlab, first_only);
if (result != NULL) {
assert(gch->is_in_reserved(result), "result not in heap");
return result;
}
if (GC_locker::is_active_and_needs_gc()) {
...
// 5.没有达到堆最大值,尝试扩容
if (!gch->is_maximal_no_gc()) {
// Try and expand heap to satisfy request
result = expand_heap_and_allocate(size, is_tlab);
// result could be null if we are out of space
if (result != NULL) {
return result;
}
}
}
...
}
// 6.发起GC
VM_GenCollectForAllocation op(size,
is_tlab,
gc_count_before);
VMThread::execute(&op);
if (op.prologue_succeeded()) {
result = op.result();
if (op.gc_locked()) {
assert(result == NULL, "must be NULL if gc_locked() is true");
continue; // retry and/or stall as necessary
}
...
const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded();
const bool softrefs_clear = all_soft_refs_clear();
// 7.如果gc开销超过限制并且软引用已经清除过则返回null
if (limit_exceeded && softrefs_clear) {
...
return NULL;
}
// 8.返回执行虚拟机分配失败处理的结果
return result;
}
...
}
3. 执行垃圾回收
HeapWord* GenCollectorPolicy::satisfy_failed_allocation(size_t size,
bool is_tlab) {
...
HeapWord* result = NULL;
...
if (GC_locker::is_active_and_needs_gc()) {
// 1.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 */)) {
// 2.执行ygc,不清理软引用
gch->do_collection(false /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
} else {
// 3.尝试进行full gc,不回收软引用
gch->do_collection(true /* full */,
false /* clear_all_soft_refs */,
size /* size */,
is_tlab /* is_tlab */,
number_of_generations() - 1 /* max_level */);
}
// 4.尝试分配空间
result = gch->attempt_allocation(size, is_tlab, false /*first_only*/);
if (result != NULL) {
return result;
}
// 5.扩展堆大小
result = expand_heap_and_allocate(size, is_tlab);
if (result != NULL) {
return result;
}
// 如果到了这一步说明真的没有内存了。
{
IntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
// 6.full gc压缩算法并清理软引用
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) {
return result;
}
// OOM了
return NULL;
}