JAVA的垃圾收集器与内存分配策略【一篇文章直接看懂】( 六 )


内存占用角度:G1的卡表更复杂,每个都要有卡表,而CMS只有一份只处理老年代对新生代的引用执行负载:CMS使用写后屏障,G1使用写后维护卡表的同时,因使用SATB,所以使用写前屏障跟踪并发时的并发情况 。G1把写前和写后要做的事放入类似消息队列的结构中,进行异步处理 。
因此小内存选CMS,大内存选G1,平衡点在6-8GB之间
低延迟垃圾收集器
GC的衡量标准:内存占用()、吞吐量()、延迟(),随着计算机硬件的发展,延迟的重要性日益凸显,越发备受关注 。
各收集器的并发情况:
浅色为必须挂起用户线程,深色表为GC与用户并发工作 。
在CMS/G1之前都要“Stop The World”停顿,在CMS/G1分别使用增量更新/原始快照,实现了标记阶段的并发 。但是CMS中整理碎片空间也要“Stop The World”、G1可以按来回收,但是也是需要在筛选回收时暂停的 。
目前/ZGC都是实验阶段的GC
收集器
在商用被ban了
像是G1的下一代继承整,有着类似的堆内存布局 。在管理内存的领域改进如下:
支持并发的整理算法默认不适用分代 收集摒弃了记忆集,改用链接矩阵( ):N有对M的引用->标记[N][M] 。
步骤:
初始标记( ):标记GC Root直接相关联的对象,短停并发标记( ):标记对象图中可达对象,与用户并发最终标记(Final ):处理剩余的SATB扫描,统计出回收价值最高的,组成回收集,小暂停
---------以上与G1相同----------
并发清理( ):清除没有存活对象的【称为】并发回收( ):核心差异,先复制回收集中存活的对象到空中,使用读屏障和“ 转发指针解决,时间取决于回收集大小初始引用更新():并未操作,只是为了确保GC完成了对象移动工作,有短暂停顿并发引用更新():开始更新引用,但是是按照内存物理地址的顺序搜索引用类型后修改最终引用更新(Final):修改堆中的引用,要修改GC Root中的引用,最后一次停顿,与GC Root有关并发清除( ):回收集中的所有都没有存活对象了,直接全回收掉
黄色:被选入回收集的
绿色:还存活的对象
蓝色:用户可以用来分配对象的
支持并行整理的核心概念:
在原有对象结构前添加一个在不处于并发移动时,引用指向对象自己的字段 。【像句柄定位】
存在的问题:
执行效率的问题:保证并发时的访问一致性,需要设置读、写屏障拦截,与其他GC模型相比,加入了额外的转发处理,故而读代价很大,由此改进为基于引用访问屏障(Load),只拦截引用类型的读写操作性能表现:
未实现最大停顿在10毫秒内,高运行负担导致吞吐量下降,但是低延迟 ZGC收集器
基于内存布局,不设分代,使用读屏障、染色指针和内存多重映射等技术的标记-整理算法
ZGC的具有动态性:动态创建、销毁、容量大小
并发整理算法的实现:
标志性的设计染色指针技术( ),直接把标记信息记在对象的指针上,遍历引用图来标记引用 。
64位的linux举例:
染色指针的三大优势:
对象被移走后,可以立即被释放和重用,不需要等待更新引用可以大幅减少内存屏障的使用数量 。只需要读屏障【写屏障通常是为了记录引用的变动情况】,一部分是因为染色指针,一部分是因为没有分代收集【没有跨代引用】存储结构可扩展,来记录更多的对象标记、重定位过程相关的数据 。若开发出linux前64中未使用的18位【这些不能用来寻址】
虚拟内存映射技术:
JVM重新定义指针中某几位的技术;