JVM创建对象的oom流程

创建一个对象引起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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值