1. 简介
当开发者使用JAVA语言实例化一个对象时,排除JIT的标量替换等优化手段,该对象会在JAVA Heap上分配存储空间。
分配空间时,为了提高JVM的运行效率,应当尽量减少临界区范围,避免全局锁。G1的通常的应用场景中,会存在大量的Mutator同时执行,为减少锁冲突,引入了TLAB(线程本地分配缓冲区 Thread Local Allocation Buffer)机制。
G1支持基于TLAB的快速分配,当TLAB快速分配失败时,使用TLAB外慢速分配。
2. 分配流程
空间分配的入口在instanceKlass.cpp
instanceOop InstanceKlass::allocate_instance(TRAPS) {
bool has_finalizer_flag = has_finalizer(); // Query before possible GC
int size = size_helper(); // Query before forming handle.
instanceOop i;
i = (instanceOop)Universe::heap()->obj_allocate(this, size, CHECK_NULL);
if (has_finalizer_flag && !RegisterFinalizersAtInit) {
i = register_finalizer(i, CHECK_NULL);
}
return i;
}
- 判断是否重写了finalize方法,如是,则注册finalizer
- 调用CollectedHeap::obj_allocate分配
collectedHeap.cpp
oop CollectedHeap::obj_allocate(Klass* klass, int size, TRAPS) {
ObjAllocator allocator(klass, size, THREAD);
return allocator.allocate();
}
- 调用ObjAllocator::allocate分配
memAllocator.cpp
HeapWord* MemAllocator::mem_allocate(Allocation& allocation) const {
if (UseTLAB) {
HeapWord* result = allocate_inside_tlab(allocation);
if (result != NULL) {
return result;
}
}
return allocate_outside_tlab(allocation);
}
- 如果开启了UseTLAB选项,则先尝试在TLAB中分配;JVM参数-XX:+UseTLAB、-XX:-UseTLAB开启或关闭TLAB
- 如果TLAB分配失败,则在TLAB外分配
对象堆空间分配的流程图如下:
3. TLAB分配
Eden区域是所有线程都可以访问的区域,为了快速分配内存,TLAB机制是通过给每个线程分配一个线程独享的缓冲区来减少锁的。
TLAB位于Eden区域中,所有的TLAB对于其他线程都是可见的,但是只有本地线程可以在其TLAB中分配空间。
另外,TLAB分配时,为了线程安全仍然需要加锁。
memAllocator.cpp
HeapWord* MemAllocator::allocate_inside_tlab(Allocation& allocation) const {
assert(UseTLAB, "should use UseTLAB");
// Try allocating from an existing TLAB.
HeapWord* mem = _thread->tlab().allocate(_word_size);
if (mem != NULL) {
return mem;
}
// Try refilling the TLAB and allocating the object in it.
return allocate_inside_tlab_slow(allocation);
}
- 在已有的TLAB中分配,逻辑较为简单,调用本地线程的tlab的allocate方法
- 如果在已有的TLAB中分配失败,则调用allocate_inside_tlab_slow,执行TLAB慢分配
threadLocalAllocBuffer.inline.hpp