《JVM G1源码分析和调优》 —3 G1的对象分配
第3章
G1的对象分配
对象分配直接关系到内存的使用效率、垃圾回收的效率,不同的分配策略也会影响对象的分配速度,从而影响Mutator的运行。
本章主要介绍G1的对象分配是怎样的。大体来说G1提供了两种对象分配策略:基于线程本地分配缓冲区(Thread Local Allocation Buffer,TLAB)的快速分配和慢速分配;当不能成功分配对象时就会触发垃圾回收,所以本章还总结了垃圾回收触发的时机;最后介绍了对象分配过程中涉及的参数调优。值得注意的是本章介绍的内容不仅适用于G1的对象分配,大多数调优参数也适用于其他的垃圾回收器。
3.1 对象分配概述
为了提高效率,无论快速分配还是慢速分配,都应该在STW之外调用,即都应该尽量避免使用全局锁,最好满足不同Mutator之间能并行分配且无干扰。但实际上堆空间只有一个,所以JVM的设计者致力于优秀的内存分配算法,把内存分配算法设计成几个层次,首先进行无锁分配,再进行加锁,从而尽可能地满足并行化分配。
我们以一个普通的Java对象分配为例,来梳理一下对象分配的过程。根据Java对象在JVM中的实现,JVM会先创建instanceklass,然后通过allocate_instance分配一个instanceOop。入口在InstanceKlass::allocate_instance,代码如下:
hotspot/src/share/vm/oops/instanceKlass.cpp
instanceOop InstanceKlass::allocate_instance(TRAPS) {
bool has_finalizer_flag = has_finalizer();
int size = size_helper();
KlassHandle h_k(THREAD, this);
instanceOop i;
i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
if (has_finalizer_flag && !RegisterFinalizersAtInit) {
i = register_finalizer(i, CHECK_NULL);
}
return i;
}
在CollectedHeap::obj_allocate中完成内存分配,如果成功则初始化对象;如果不成功则抛出异常。主要工作在CollectedHeap::common_mem_allocate_noinit()中,我们直接来看这个函数。该函数包含了我们上面提到的两种分配方法:TLAB快速分配allocate_from_tlab和慢速分配Universe::heap()->mem_allocate。代码如下:
hotspot/src/share/vm/gc_interface/collectedHeap.inline.hpp
HeapWord* CollectedHeap::common_mem_allocate_noinit(KlassHandle klass,
size_t size, TRAPS) {
// 省略一些检查等
……
HeapWord* result = NULL;
if (UseTLAB) {
result = allocate_from_tlab(klass, THREAD, size);
if (result != NULL) return result;
}
bool gc_overhead_limit_was_exceeded = false;
result = Universe::heap()->mem_allocate(size, &gc_overhead_limit_was_exceeded);
if (result != NULL) {
……
return result;
}
// 不成功抛出异常等
……
}
对象分配相对来说逻辑清晰,图3-1为对象分配的全景流程图。
图3-1 对象分配流程图
- 点赞
- 收藏
- 关注作者
评论(0)