从零开始看源码,旨在从源码验证书上的结论,探索书上未知的细节。有疑问欢迎留言探讨
个人源码地址:https://github.com/FlashLightNing/openjdk-notes
还有一个openjdk6,7,8,9的地址:https://github.com/dmlloyd/openjdk
jvm源码阅读笔记[1]:如何触发一次CMS回收
jvm源码阅读笔记[2]:你不知道的晋升阈值TenuringThreshold详解
jvm源码阅读笔记[3]:从内存分配到触发GC的细节
jvm源码阅读笔记[4]:从GC说到vm operation
jvm源码阅读笔记[5]:内存分配失败触发的GC究竟对内存做了什么?
除了第一篇说到的,对于使用cms回收的应用,会有线程轮询判断老年代是否满足GC的条件,若满足,则会触发一次cms老年代的回收。
针对年轻代,更常见的是,线程优先在eden区分配对象的时候,若eden区空间不足,则会触发一次young gc。若不允许担保失败,则还可能转为一次full gc。那么,今天就来看看这种内存分配不足触发GC的过程。
以下是collectedHeap.inline.hpp中的分配的代码。
oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
debug_only(check_for_valid_allocation_state());
assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");//校验在GC的时候不会进行内存分配
assert(size >= 0, "int won't convert to size_t");
HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
post_allocation_setup_obj(klass, obj, size);
NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
return (oop)obj;
}
collectedHeap定义了Java堆的实现,定义了堆必须实现的功能,如创建TLAB,内存分配等基本功能。然后其他类通过继承collectedHeap类,实现了几种具体的堆类型,主要有ParallelScavengeHeap,G1CollectedHeap等。这些细节以后再写。
从源码中可以看到,首先是一些简单的校验,如当前堆不处于GC状态,分配的大小>0。然后再调用common_mem_allocate_init方法进行内存分配,再是调用post_allocation_setup_obj做一些初始化的工作,如设置对象头信息等。
来看看common_mem_allocate_init方法:
HeapWord* CollectedHeap::common_mem_allocate_init(KlassHandle klass, size_t size, TRAPS) {
HeapWord* obj = common_mem_allocate_noinit(klass, size, CHECK_NULL);
init_obj(obj, size);//字节填充和对齐
return obj;
}
它先是调用common_mem_allocate_noinit方法申请了内存空间,然后调用init_obj方法进行初始化,这里的初始化主要是为申请出来的这块空间填充0字节和字节对齐。
还是来看看common_mem_allocate_noinit方法吧。
HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass, size_t size, TRAPS) {
CHECK_UNHANDLED_OOPS_ONLY(THREAD->clear_unhandled_oops();)
if (HAS_PENDING_EXCEPTION) {
NOT_PRODUCT(guarantee(false, "Should not allocate with exception pending"));
return NULL; // caller does a CHECK_0 too
}
HeapWord* result = NULL;
if (UseTLAB) {
//在tlab里分配
result = allocate_from_tlab(klass, THREAD, size);
if (result != NULL) {
assert(!HAS_PENDING_EXCEPTION,
"Unexpected exception, will result in uninitialized storage");
return result;
}
}
bool gc_overhead_limit_was_exceeded = false;
//在堆中分配
result = Univer