EpsilonGC支持普通内存分配和TLAB内存分配,前者接口是mem_allocate(),后者是allocate_new_tlab()。
3.1 普通内存分配 // hotspot\share\gc\epsilon\epsilonHeap.hpp HeapWord* EpsilonHeap::mem_allocate(size_t size, bool *gc_overhead_limit_was_exceeded) { *gc_overhead_limit_was_exceeded = false; return allocate_work(size); } HeapWord* EpsilonHeap::allocate_work(size_t size) { // 无锁并发分配 HeapWord* res = _space->par_allocate(size); // 如果分配失败,循环扩容 while (res == NULL) { MutexLockerEx ml(Heap_lock); // 先扩容(之前virtual space有一部分是reserved但是没有committed) // 剩余可用空间大小 size_t space_left = max_capacity() - capacity(); // 需要空间大小 size_t want_space = MAX2(size, EpsilonMinHeapExpand); if (want_space < space_left) { bool expand = _virtual_space.expand_by(want_space); } else if (size < space_left) { bool expand = _virtual_space.expand_by(space_left); } else { // 如果扩容失败则分配失败,返回null return NULL; } // 扩容成功,设置virtual_space的committed尾为新大小 _space->set_end((HeapWord *) _virtual_space.high()); // 再次尝试分配内存 res = _space->par_allocate(size); } size_t used = _space->used(); // 分配成功,更新perdata信息 { size_t last = _last_counter_update; if ((used - last >= _step_counter_update) && Atomic::cmpxchg(used, &_last_counter_update, last) == last) { _monitoring_support->update_counters(); } } // 输出堆占用情况 { size_t last = _last_heap_print; if ((used - last >= _step_heap_print) && Atomic::cmpxchg(used, &_last_heap_print, last) == last) { log_info(gc)("Heap: " SIZE_FORMAT "M reserved, " SIZE_FORMAT "M (%.2f%%) committed, " SIZE_FORMAT "M (%.2f%%) used", max_capacity() / M, capacity() / M, capacity() * 100.0 / max_capacity(), used / M, used * 100.0 / max_capacity()); } } return res; }为了看到扩容的发生,我们可以修改一下代码,在循环扩容处添加日志记录:
log_info(gc)("Heap expansion: committed %lluM, needs %lluM, reserved %lluM", capacity() / M, want_space/M, max_capacity() / M);编译得到JVM,然后准备一段Java代码:
package com.github.kelthuzadx; class Foo{ private static int _1MB = 1024*1024; private byte[] b = new byte[_1MB*200]; } public class GCBaby { public static void main(String[] args) { new Foo();new Foo(); } }启动JVM时添加参数-XX:+UnlockExperimentalVMOptions -Xms128m -Xmx512m -XX:+UseEpsilonGC -Xlog:gc*=info,最终我们可以看到为了分配400M的对象,初始大小128M的堆进行了3次扩容:
[8.904s][info][gc] Heap expansion: committed 128M, needs 128M, reserved 512M [8.904s][info][gc] Heap: 512M reserved, 256M (50.00%) committed, 207M (40.51%) used [9.010s][info][gc] Heap expansion: committed 256M, needs 128M, reserved 512M [9.010s][info][gc] Heap expansion: committed 384M, needs 128M, reserved 512M [9.011s][info][gc] Heap: 512M reserved, 512M (100.00%) committed, 407M (79.57%) used 3.2 TLAB内存分配 // hotspot\share\gc\epsilon\epsilonHeap.hpp HeapWord* EpsilonHeap::allocate_new_tlab(size_t min_size, size_t requested_size, size_t* actual_size) { Thread* thread = Thread::current(); bool fits = true; size_t size = requested_size; size_t ergo_tlab = requested_size; int64_t time = 0; // 如果启用TLAB if (EpsilonElasticTLAB) { // 为线程设置TLAB ergo_tlab = EpsilonThreadLocalData::ergo_tlab_size(thread); // 如果启用TLAB衰减,则默认1s后TLAB大小重置为0 if (EpsilonElasticTLABDecay) { int64_t last_time = EpsilonThreadLocalData::last_tlab_time(thread); time = (int64_t) os::javaTimeNanos(); if (last_time != 0 && (time - last_time > _decay_time_ns)) { ergo_tlab = 0; EpsilonThreadLocalData::set_ergo_tlab_size(thread, 0); } } // 如果TLAB大小能容纳下本次分配,就在TLAB上分配 // 否则弹性的增大TLAB大小,所谓的弹性增大默认是1.1倍扩大 fits = (requested_size <= ergo_tlab); if (!fits) { size = (size_t) (ergo_tlab * EpsilonTLABElasticity); } } size = MAX2(min_size, MIN2(_max_tlab_size, size)); size = align_up(size, MinObjAlignment); if (log_is_enabled(Trace, gc)) { ResourceMark rm; log_trace(gc)("TLAB size for \"%s\" (Requested: " SIZE_FORMAT "K, Min: " SIZE_FORMAT "K, Max: " SIZE_FORMAT "K, Ergo: " SIZE_FORMAT "K) -> " SIZE_FORMAT "K", thread->name(), requested_size * HeapWordSize / K, min_size * HeapWordSize / K, _max_tlab_size * HeapWordSize / K, ergo_tlab * HeapWordSize / K, size * HeapWordSize / K); } // 准备就绪,分配内存 HeapWord* res = allocate_work(size); if (res != NULL) { // 分配成功 *actual_size = size; if (EpsilonElasticTLABDecay) { EpsilonThreadLocalData::set_last_tlab_time(thread, time); } if (EpsilonElasticTLAB && !fits) { EpsilonThreadLocalData::set_ergo_tlab_size(thread, size); } } else { // 分配失败 if (EpsilonElasticTLAB) { EpsilonThreadLocalData::set_ergo_tlab_size(thread, 0); } } return res; } 4. 垃圾回收