在实际的内存使用中,会出现寄存器、调用栈、全局变量空间等作为GC root即不明确的根,而此时GC是无法识别出当前root是指针还是非指针。
保守,顾名思义,就是宁可漏掉一千,不能错杀一个。这是什么意思呢?学过c/c++都知道,如果有一个整数值,那么这个整数值是指针还是一个具体的数值呢?单纯从这个值本身来看,是无法进行判断的。这也就是保守式GC的原因,遇到这种问题怎么办?保守式GC会利用几种方法来进行判别?
1、是否对齐,这个对齐就是常说的字节对齐,在32位的机器上是4个字节;64位是8个字节。
2、是否指向堆的位置,这个好理解,是否在预告指定的内存堆内,是的话一定是指针。
3、是否是对象的头部,这个和对象对齐有关。
好,既然可以用这几个初步的简单的方法来判断指针和非指针,那么就一定会遇到不属于这三种情况的状况也就是“貌似指针的非指针”。什么意思呢,就是上述三个条件里,有可能都满足但却无法判定,比如有可能出现数值和指向位置重合的情况,那么它到底是指针还是非指针呢?保守式GC就是把它们都当成指针。
有保守式GC就会有准确式GC,恰好相反,准确GC可以准确的判断指针和非指针,它使用的判断方法是:
1、做标记,这个方法最简单实用,但可能浪费空间。
2、低1位置位,主要是对数据数值处理时的安全性考虑。
3、不使用保守式GC中的栈、寄存器这类的存储空间为根。
保守GC的优点:
1、语言处理部分实现容易,基本和GC完全解耦。
保守GC的缺点:
1、对指针和非指针的判断需要成本。
2、错误识别引起内存泄露。
3、在GC算法中由于其自身的特点,应用场景有限。比如因为指针判断问题对象无法移动。
而准确式的GC的优缺点恰好相反,这里就不再赘述。
改进的方法:
对于保守式GC最主要的问题是错误判断指针导致对象的移动产生的不可预测的后果,那么可不可以有一种方式来回避这种情况呢?不知道大家听说过计算机内的一句名言没有:“如果问题不好解决就加一层”。这里也是,增加一个句柄指向对象。这样基本就解决了不可移动的问题。不过,层越多,效率越差。
同样还可以使用黑名单技术,这个就比较好理解了,把相关的模糊的地址名单形成一个黑名单来具体处理。
保守式GC其实更多是一种策略,而不是一种GC算法。所以从理论讲,只要是符合其应用策略的场景都可以使用。特别是改进后的保守式GC,几乎就可以做为一种完全的策略来使用了。有兴趣可以看看MostlyCopyingGC这个保守式GC的算法。
五、总结术与道,自古就争论不休。学武术的人都知道一句话“练拳不练功,到老一场空;练功不练拳,好似无舵船”。其实辩证的看问题,在学习上也是一个道理,彼之蜜糖,吾之毒药。一味的单纯指责某个算法好与坏,本身就是一种缘木求鱼的做法。实践是检验真理的唯一标准,实事求是,这才是真正的一种做学问搞技术的态度。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)