gc可达性指针查找

回收期需要通过指针查找来确定对象的可达性。某些回收算法需要精确掌握程序中所有指针的信息。特别是对于移动式回收器而言, 如果需要将某一对象从地址x移动到新地址 x’,则必须将所有指向x的指针更新到x’。

一. 保守式

回收器可以掌握组成堆的内存区域集合, 甚至知道这些区域中哪些部分已经分配出去, 因而它可以快速排除掉必然不是指针的值。 通过对gcRoot扫描,判断指针是否指向堆中已分配的区域,在堆中是否对齐,是否指向对象头。到这一步能基本判断该指针是否指向堆中某一对象。

优点:实现简单,无需记录额外的信息来精确指针信息。不适用于移动式回收器(标记整理,复制)。对于类型不确定的语言只能使用保守式(如C&C++)。

缺点:可能存在误判,会将某一非指针的值当作指针。

优化:

  • 黑名单机制,非指针的值a可能导致回收器错误地保留一块不可达的内存m,若检测到m还未分配出去但可能在将来被分配出去,将m设为不可被分配,直到a被销毁。
  • 内存块分区,不包含指针的对象与包含指针的对象。能够加速指针查找效率。此方法同样适用精确式指针查找。

二. 精确式

准确式GC能够正确识别指针和非指针的GC。正确的根的创建方法是依赖于语言处理程序的实现的。我们可以通过打标签、页簇等方法来实现。 其优点就是完全能够识别指针,能够使用复制算法等需要移动对象的算法。但是在创建准确式GC时,语言处理程序必须对GC进行一些支援,而且创建正确的根就必须付出一定的代价。

打标签:指针位窃取,指针最高位作为标签,为0时代表真实指针,为1时代表int等基本类型。但这 一方案减少了我们可以直接表达的整数范围。实际上64位系统中指针能表达的范围非常大,在不使用指针压缩的情况下,linux 64位上只用到了48位虚拟地址,43位物理地址。

页簇映射:用额外的空间记录某个值是否为指针或者指针类型。它能够表达int等原生类型,而且只需扫描标记有指针的页,但映射关系通常是动态的且获取标签信息需要额外的内存加载操作。

对于java语言,它是动态类型确定的,即可以在运行时知道指针指向对象的类型。内部使用了OopMap代表了栈上指针到对象的映射。gc 发生时,程序首先运行到最近的一个safepoint停下来,然后更新自己的 OopMap ,记下栈上哪些位置代表着引用。枚举根节点时,递归遍历每个栈帧的 OopMap ,通过栈中记录的被引用对象的内存地址,即可找到这些对象。

safepoint在java语言中多处用到,如垃圾回收,对象分配,加锁等。

对于gc的safepoint的检查点位置主要在:
1、循环的末尾(int类型或更小范围循环可能会被JIT优化掉,或者每n轮迭代设置一次,比如 for(int i=1000;;) safepoint检查点可能没有safepoint,可能100轮循环有一个。编码时若循环中有大量不确定时长的连接,可以将int改为long来禁用safepoint优化)
2、方法临返回前 / 调用方法的call指令后
3、可能抛异常的位置

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值