苏州企业网站优化,伦敦 wordpress 设计,一家专门做爆品印刷的网站,购物网站类型JVM是如何解决跨代引用的#xff1f; 跨代引用问题如何解决跨代引用记忆集#xff08;Remembered Set#xff09;卡表 写屏障 跨代引用问题
假如要现在进行一次只局限于新生代区域内的收集(Minor gc)#xff0c;但新生代的对象1在老年代中被引用#xff0c;为了找出该区域… JVM是如何解决跨代引用的 跨代引用问题如何解决跨代引用记忆集Remembered Set卡表 写屏障 跨代引用问题
假如要现在进行一次只局限于新生代区域内的收集(Minor gc)但新生代的对象1在老年代中被引用为了找出该区域新生代中所有的存活对象不得不在固定的gc roots之外在额外遍历整个老年代中所有对象来确保可达性分析结果的正确性。 遍历整个老年代所有对象的方案虽然可行但是会给内存回收带来很大的性能负担。
实时上并不是只有新生代、老年代才有跨代引用的问题所有涉及部分区域手机行为的垃圾收集器典型的如G1、ZGC收集器都会面临同样的问题。
如何解决跨代引用
先说结论JVM是使用 写屏障 卡表 解决的。
首先跨代引用是少数的例如某个新生代对象存在跨代引用由于老年代对象难以消亡就会导致新生代对象在收集时同样得已存活进而在年龄增长之后晋升到老年代中了。所以就不用为了少量的跨代引用扫描整个老年代只需要在新生代建立一个全局的数据结构(该结构被称为 记忆集Rember Set)标识出老年代的哪一块内存存在跨代引用此后发生minor gc时只有包含了跨代引用的小块内存里的对象才会被加入gc root进行扫描。个人理解card table是用来划分老年代的即把老年代划分多个大小相等的连续区域而Rember set中记录了卡表的位置。
记忆集Remembered Set
一种记录 从非收集区域(如老年代) 指向 收集区域(如年轻代)的指针集合的抽象数据结构在对象层面来说就是非收集区域对收集区域对象的引用记录。 它存放在收集区域比如在新生代里面存放着老年代对新生代的每一个引用这样在收集新生代的时候我们就可以根据记忆集知道哪些对应被老年代对象引用了不能回收这就解决了跨代引用过的问题。
记忆集根据记录的精度可以分三类实现方式:
字长精度记录的是老年代指向新生代地址。对象精度记录的是老年代引用的新生代对象。卡精度记录的是新生代一段地址是否存在被老年代引用的记录
卡表
是以第三种卡精度的方式实现的记忆集也是目前最常用的方式。记忆集是抽象的概念而卡表就是记忆集的一种具体实现。
卡表最简单的形式可以是一个字节数组HotSpot就是这样实现的。 CARD_TABLE [this address 9] 0;
把地址的值右移9位相当于除于512就是卡表索引每字节512为一组对应卡表同一个元素一组就是一个卡页如果这个卡页中只要有一个对象被其他区域对象所引用对应卡表元素的值就变成1也就是所谓的元素变脏。
在垃圾回收时只要筛选出卡表中变脏的元素就能轻易得出哪些卡页对应的内存包含跨代指针把他们加入GC Rootsz中一并扫描。
写屏障
可以看成是虚拟机层面在“引用类型字段赋值”这个动作的AOP切面引用对象赋值的时候产生一个环形通知进行一些额外的处理这样就是引用对象赋值这个操作都在写屏障的覆盖范围内赋值前的写屏障叫写前屏障赋值后的写屏障叫写后屏障。 卡表的更新就是通过写屏障写入的。