ZGC的对象分配流程大体与G1类似。分配流程图在JVM G1 源码分析(二)- 对象的堆空间分配内。
主要代码在src/hotspot/share/gc/shared目录下,为多个GC算法的共用代码。
ZGC定制逻辑由gc shared代码调用ZCollectedHeap、ZHeap等ZGC派生类实现。
当线程的TLAB可用内存不足时,MemAllocator的allocate_inside_tlab_slow会调用ZCollectedHeap的allocate_new_tlab申请新的TLAB。
zCollectedHeap.cpp
HeapWord* ZCollectedHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) {
const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(requested_size));
const uintptr_t addr = _heap.alloc_tlab(size_in_bytes);
if (addr != 0) {
*actual_size = requested_size;
}
return (HeapWord*)addr;
}
alloc_tlab在校验size合法性后,调用ZObjectAllocator的alloc_object进行分配。
zHeap.inline.hpp
inline uintptr_t ZHeap::alloc_tlab(size_t size) {
guarantee(size <= max_tlab_size(), "TLAB too large");
return _object_allocator.alloc_object(size);
}
ZObjectAllocator的alloc_object根据需要分配的size分别调用alloc_small_object、alloc_medium_object、alloc_large_object,我会在mem_allocate章节逐一介绍。
zObjectAllocator.cpp
uintptr_t ZObjectAllocator::alloc_object(size_t size, ZAllocationFlags flags) {
if (size <= ZObjectSizeLimitSmall) {
// Small
return alloc_small_object(size, flags);
} else if (size <= ZObjectSizeLimitMedium) {
// Medium
return alloc_medium_object(size, flags);
} else {
// Large
return alloc_large_object(size, flags);
}
}
uintptr_t ZObjectAllocator::alloc_object(size_t size) {
assert(ZThread::is_java(), "Must be a Java thread");
ZAllocationFlags flags;
flags.set_no_reserve();
if (!ZStallOnOutOfMemory) {
flags.set_non_blocking();
}
return alloc_object(size, flags);
}
当TLAB分配失败时,MemAllocator的allocate_outside_tlab会调用ZCollectedHeap的mem_allocate进行慢分配。
zCollectedHeap.cpp
HeapWord* ZCollectedHeap::mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) {
const size_t size_in_bytes = ZUtils::words_to_bytes(align_object_size(size));
return (HeapWord*)_heap.alloc_object(size_in_bytes);
}
zHeap.inline.hpp
inline uintptr_t ZHeap::alloc_object(size_t size) {
uintptr_t addr = _object_allocator.alloc_object(size);
assert(ZAddress::is_good_or_null(addr), "Bad address");
if (addr == 0) {
out_of_memory();
}
return addr;
}
根据需要分配的size大小,决定调用哪个函数进行分配。
zObjectAllocator.cpp
uintptr_t ZObjectAllocator::alloc_object(size_t size, ZAllocationFlags flags) {
if (size <= ZObjectSizeLimitSmall) {
// Small
return alloc_small_object(size, flags);
} else if (size <= ZObjectSizeLimitMedium) {
// Medium
return alloc_medium_object(size, flags);
} else {
// Large
return alloc_large_object(size, flags);
}
}
alloc_small_object和alloc_medium_object最后都会调用alloc_object_in_shared_page
zObjectAllocator.cpp
uintptr_t ZObjectAllocator::alloc_object_in_shared_page(ZPage** shared_page,
uint8_t page_type,
size_t page_size,
size_t size,
ZAllocationFlags flags) {
uintptr_t addr = 0;
ZPage* page = *shared_page;
if (page != NULL) {
addr = page->alloc_object_atomic(size);
}
if (addr == 0) {
// Allocate new page
ZPage* const new_page = alloc_page(page_type, page_size, flags);
if (new_page != NULL) {
// Allocate object before installing the new page
addr = new_page->alloc_object(size);
retry:
// Install new page
ZPage* const prev_page = Atomic::cmpxchg(new_page, shared_page, page);
if (prev_page != page) {
if (prev_page == NULL) {
// Previous page was retired, retry installing the new page
page = prev_page;
goto retry;
}
// Another page already installed, try allocation there first
const uintptr_t prev_addr = prev_page->alloc_object_atomic(size);
if (prev_addr == 0) {
// Allocation failed, retry installing the new page
page = prev_page;
goto retry;
}
// Allocation succeeded in already installed page
addr = prev_addr;
// Undo new page allocation
ZHeap::heap()->undo_alloc_page(new_page);
}
}
}
return addr;
}
alloc_object_atomic没有锁,而是通过自旋+CAS实现并发控制,自旋使用CAS分配对象,直到成功或Page没有足够的空间
zPage.inline.hpp
inline uintptr_t ZPage::alloc_object_atomic(size_t size) {
assert(is_allocating(), "Invalid state");
const size_t aligned_size = align_up(size, object_alignment());
uintptr_t addr = top();
for (;;) {
const uintptr_t new_top = addr + aligned_size;
if (new_top > end()) {
// Not enough space left
return 0;
}
const uintptr_t prev_top = Atomic::cmpxchg(new_top, &_top, addr);
if (prev_top == addr) {
// Success
return ZAddress::good(addr);
}
// Retry
addr = prev_top;
}
}
大对象分配略有不同
zObjectAllocator.cpp
uintptr_t ZObjectAllocator::alloc_large_object(size_t size, ZAllocationFlags flags) {
assert(ZThread::is_java(), "Should be a Java thread");
uintptr_t addr = 0;
// Allocate new large page
const size_t page_size = align_up(size, ZPageSizeMin);
ZPage* const page = alloc_page(ZPageTypeLarge, page_size, flags);
if (page != NULL) {
// Allocate the object
addr = page->alloc_object(size);
}
return addr;
}
OpenJDK 12 源代码