图解JVM如何解决对象跨代引用的问题

开发 前端
 记忆集是一种概念,在hotspot使用名为“卡表”(Cardtable)的方式实现记忆集,它也是目前最常用的一种方式。卡表使用一个字节数组来实现:CARD_TABLE[],每个元素对应着其标识的内存区域一块特定大小的内存块,我们称之为“卡页”。

    在新生代做GCRoots可达性扫描过程中,可能会碰到跨代引用的对象的问题,如下图所示:

图片图片

    在新生代扫面的时候会扫描不到D对象,如果这个D对象不去老年代扫描是否有被引用,那么就会无法触达,如下如所示:

图片图片

    但是D对象是有被引用的,如果直接回收D对象就会造成一些意想不到的问题,如果为了扫描D对象是否存在跨代引用而对老年代整体扫描一遍,就会带来整个垃圾回收的效率低下的问题。

    为了解决跨代引用的问题,可以在新生代可以引入RememberSet(记录从非收集区到收集区的指针集合)的数据结构,称为记忆集,这样避免把整个老年代加入到GCRoots扫描范围中,如下所示:

图片图片

    记忆集是一种概念,在hotspot使用名为“卡表”(Cardtable)的方式实现记忆集,它也是目前最常用的一种方式。卡表使用一个字节数组来实现:CARD_TABLE[],每个元素对应着其标识的内存区域一块特定大小的内存块,我们称之为“卡页”,如下图所示:

图片图片

    将老年代按照一个卡页大小(512字节)分成n个区域,这个区域的地址信息都记录到卡表中。当某个区域中出现跨代引用的时候,我们就在卡表中记录信息,如下所示:

图片图片

    老年代的F对象引用了年轻代的D对象,那么我们就在卡表中记录a卡页中有跨代引用(设置对应区域的值为1,如上a=1;卡页b没有跨代引用,设置b=0来表示此区域无跨代引用)。

    当年轻代做GCRoots扫描的时候,我们去卡表中查询哪些区域存在跨代的对象,然后判断这个对象是否还继续存活,如下所示:

图片图片

    一个卡页中可包含多个对象,只要有一个对象存在跨代引用,那么其对应在卡表中的元素标识就设置成1,表示该区域存在跨代引用,否则为0。GC时只要筛选本收集区的卡表中为1区域中的元素加入GCRoots里(如上图中a=1就被筛选出来做GCRoots)。

    通过卡表的方式我们就避免了大规模的扫描老年代对象,假设老年代有上万的对象存活,年轻代之后几十个存活对象,通过卡表我们只需要扫面少部分的老年代对象,大大的提升垃圾收集的效率。

    在hotspot使用写屏障维护卡表中数据状态,当老年代引用了新生代的对象时候,底层会维护将卡表中的对应的区域设置为1。

责任编辑:武晓燕 来源: 龙虾编程
相关推荐

2024-10-29 16:41:24

SpringBoot跨域Java

2021-06-06 13:05:15

前端跨域CORS

2022-03-11 10:01:47

开发跨域技术

2011-05-17 13:22:50

SQL对象名无效

2022-02-22 11:54:05

跨域项目前后端

2010-03-18 14:54:57

Java SynDem

2023-04-07 10:51:39

2022-09-07 07:05:25

跨域问题安全架构

2023-02-15 07:03:41

跨域问题面试安全

2010-04-29 17:46:31

Oracle死锁

2012-09-05 11:09:15

SELinux操作系统

2022-10-13 14:11:29

浏览器域名端口

2021-10-20 20:27:55

MySQL死锁并发

2009-09-21 17:10:14

struts Hibe

2017-10-17 09:21:06

2010-03-11 18:09:33

Python正则表达式

2013-05-21 10:49:59

Windows硬件冲突

2017-07-20 07:30:16

大数据数据互联网

2018-04-09 16:00:30

Windows 10Windows更新

2011-08-08 10:29:12

MySQL
点赞
收藏

51CTO技术栈公众号