深入解析java虚拟机:垃圾回收,Epsilon GC,能学会真的赚了

1495 篇文章 10 订阅
1493 篇文章 14 订阅

Epsilon GC

源码结构

Epsilon GC源于JEP 318,它使用-XX:+UseEpsilonGC开启,是一个无操作(No-op)的垃圾回收器。所谓无操作是指它只负责分配内存但是没有对象回收行为,当Java堆耗尽时直接终止JVM。Epsilon GC看似没有意义,毕竟一个不会回收对象的垃圾回收器在内存有限的今天是不可能用于生产环境的,但是Epsilon GC是一个很好的学习示例,可以指导我们了解在HotSpot VM中实现一个最小垃圾回收器需要做哪些工作。它的源码位于gc/epsilon:

├── epsilonArguments.cpp

├── epsilonArguments.hpp # GC参数,如是否使用TLAB、是否开启EpsilonGC等

├── epsilonBarrierSet.cpp

├── epsilonBarrierSet.hpp # GC barrier

├──
epsilonCollectorPolicy.hpp # 垃圾回收策略,如堆初始大小、最大最小值等

├── epsilonHeap.cpp

├── epsilonHeap.hpp # Epsilon GC的堆

├── epsilonMemoryPool.cpp

├── epsilonMemoryPool.hpp # 堆内存的使用情况、GC次数、上次GC时间等

├── epsilonMonitoringSupport.cpp

├──
epsilonMonitoringSupport.hpp # PerfData支持

├──
epsilonThreadLocalData.hpp # 对象在TLAB分配

├── epsilon_globals.hpp # Epsilon GC特定虚拟机参数└── vmStructs_epsilon.hpp # Serviceability Agent支持

EpsilonHeap

每个垃圾回收器都抽象出了自己的Java堆结构,包含最重要的对象分配和回收垃圾接口,如Epsilon GC使用EpsilonHeap;Serial GC使用SerialHeap;CMS GC使用CMSHeap。其中,EpsilonHeap结构如代码清单10-5所示:

代码清单10-5 EpsilonHeap

class EpsilonHeap : public CollectedHeap {
private:
EpsilonCollectorPolicy* _policy; // 回收器策略
SoftRefPolicy _soft_ref_policy; // 软引用清除策略
EpsilonMonitoringSupport* _monitoring_support; // perfdata支持
MemoryPool* _pool; // 感知内存池使用情况
GCMemoryManager _memory_manager; // 内存管理器
ContiguousSpace* _space; // 实际堆空间
VirtualSpace _virtual_space; // 虚拟内存
size_t _max_tlab_size; // 最大TLAB
size_t _step_counter_update; // perfdata更新频率
size_t _step_heap_print; // 输出堆信息频率
int64_t _decay_time_ns; // TLAB大小衰减时间
volatile size_t _last_counter_update; // 最后一次perdata更新
volatile size_t _last_heap_print; // 最后一次输出堆信息public:
virtual HeapWord* mem_allocate(...); // 内存分配
virtual HeapWord* allocate_new_tlab(...); // TLAB分配
virtual void collect(...); // System.gc触发
virtual void do_full_collection(...); // 普通垃圾回收
...
};

EpsilonHeap继承自CollectedHeap,表示可用于垃圾回收的Java堆,它实现了垃圾回收的部分常用操作,剩下的工作留给纯虚函数,需要子类具体实现。代码清单10-5所示的EpsilonHeap实现了CollectedHeap的所有纯虚函数,换句话说,EpsilonHeap实现了一个最小化的Java堆所必须实现的功能。出于这个原因,用户如果想为HotSpot VM定制或实现一个新的垃圾回收器,可以仿照Epsilon GC实现自己的功能。

对象分配

前面代码清单10-5省略了大部分纯虚函数的实现,只保留了重要的几个。这里将介绍mem_allocate(),表示内存分配。第3章曾提到,当虚拟机想在Java堆上分配对象时,它会找到oop对应的klass,并调用
InstanceKlass::allocate_instance(),由该函数调用Java堆的内存分配接口,即mem_allocate(),分配新的内存以容纳对象。mem_allocate的使用如代码清单10-6所示:

代码清单10-6 EpsilonHeap::mem_allocate

HeapWord* EpsilonHeap::mem_allocate(...) {
*gc_overhead_limit_was_exceeded = false;
return allocate_work(size);
}
HeapWord* EpsilonHeap::allocate_work(size_t size) {
// 分配内存(Lock free)
HeapWord* res = _space->par_allocate(size);
// 当分配失败时,尝试扩容,然后再次尝试分配
while (res == NULL) {
MutexLockerEx ml(Heap_lock);
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 {
return NULL;// 没有剩余空间,分配失败
}
// 修改堆结束位置,即扩容
_space->set_end((HeapWord *) _virtual_space.high());
// 再次尝试内存分配
res = _space->par_allocate(size);
}size_t used = _space->used();
... // 分配成功,输出log信息
return res;
}

作为虚拟机外部世界与垃圾回收器的代理人,mem_allocate调用GC分配一片内存,由InstanceKlass获取mem_allocate分配到的内存,并用对象数据填充这段内存。

回收垃圾

正如之前所说,Epsilon GC是一个无操作垃圾回收器,如图10-1所示。

图10-1 Epsilon GC

EpsilonHeap::collect()只是简单记录垃圾回收请求并更新计数。一个不能回收垃圾的垃圾回收器可以用于学习,用于即开即停客户端程序,或者用于其他特殊场景,但是在内存有限的今天,它不适用于常见生产环境。期待Epsilon GC未来能成为一个Op-able垃圾回收器。

本文给大家讲解的内容是深入解析java虚拟机:垃圾回收,Epsilon GC

  1. 下篇文章给大家讲解的是深入解析java虚拟机:垃圾回收,Serial GC;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值