为啥“GC标记-清除算法”与“写时复制技术(copy-on-write)”不兼容
刚好在前一段时间买了这本书并且看了一半。
说不上一定正确只是分享一下我的见解。
题主的问题是,看不懂那段话为什么说明了 “ GC标记-清除算法”与“写时复制技术(copy-on-write) ” 不兼容。
【为啥“GC标记-清除算法”与“写时复制技术(copy-on-write)”不兼容】 换一个说法。
你硬要把标记清除算法和写时复制弄在一起行不行?
行。所谓的不兼容,意思是这样的结合方式并没有发挥到写时复制技术的优点,和不用写时复制没有太大区别。
写时复制技术的优点是什么?
fork进程的时候,内存空间是引用而不是复制的。
意味着执行完fork后的两个进程的内存指向的是同一片区域。但是进程可能会执行不同的操作,产生不同的数据,这时候才在其他空闲内存区域写入一个新的对象并改写原指针。如果两个程序的大部分内存数据都是相同的,那么这个技术能省下非常多的内存空间。
而GC标记-清除算法做了什么?
回到书本第一章第一节关于对象的 “ 头 ” 的描述。
“ ...比如将在第 2 章中介绍的 GC 标记 - 清除算法,就是在对象的头部中设置 1 个 flag (标志位)来记录对象是否已标记,从而管理各个对象。... ”(书中原话)
在每一个执行 GC 的时候,标记清除算法都会对被引用的对象进行标记操作。被引用的对象仅仅意味着这个对象不是垃圾,不能被清除,而不表示对象的内容已经被改写了。
试想一种情况:在fork后,两个程序都没有生成新的数据,也就是说所有对象的域都不变。
这时候执行一次 GC 标记-清除算法,标记阶段将所有被引用的对象的 flag 进行一个置位操作。这种操作的意义等同于改动了数据。这时候 “ 写时复制技术 ” 会判断对象已经被改动,从空闲内存中写入新的对象并改写原指针。
一次 GC 标记-清除算法 执行完以后,已经不存在共享的对象了,每一个对象都被复制了一遍。
这就是我理解的 “ 频繁发生本不应该发生的复制 ” 的原因。
以上是我的想法。
有任何错误,欢迎大家指出。
■网友
写时复制往往与引用计数结合使用,因为引用计数在发生对象拷贝时只是将其计数器加一,并没有发生实际的内存开辟和内容拷贝,当对象的成员执行写入操作时,根据对象的计数器是否大于一决定是否触发写时复制(基于引用计数的对象生命周期和引用关系是确定),写时复制技术往往能节省大量的内存空间和减少大量的拷贝动作,因为在一个复杂的对象系统中,往往存在大量的相互引用。
标记清除算法由于运行时无法确定对象的生命周期,所以发生对象拷贝时会真实地开辟内存空间和执行拷贝动作,并且对象不再被引用时、即成为垃圾时并不能立即发现触发回收,要回收该对象只能遍历完所有的对象节点标记哪些还被引用、哪些没有引用,那么没有引用的对象就可以回收了,标记清楚算法注定只能全局扫描批量发现回收没有引用的对象,所以这种GC存在卡顿现象。
上面比较了引用计数和标记清除算法,以及为什么写时复制技术不能被标记清楚算法实现。基于是否支持写时复制和对象的生命周期是否确定两点考虑,引用计数其实比标记清除好很多,但是引用计数存在循环引用的问题,即一个对象的成员引用了该对象本身,当该对象不再被引用时,由于计数器没有减到零,所以该对象永远都不会被回收,这样就造成了内存泄露,如果有方法在执行对象赋值时自动检测是否会发生循环引用并立即处理,那么引用计数就完美了,事实上确实存在自动检测循环引用的方法。
引用计数和循环引用原理如下:
class a { var v; };
a1=new a; //A引用计数为1
a2=a1; //A引用计数为2
a1.v=0; //触发写时复制,a1指向一个新内存空间的对象B并且引用计数为1,而a2指向的A引用计数减到1
推荐阅读
- 为啥看到书柜上的藏书会有心旷神怡的感觉
- 为啥知乎上普便有一种【我在北上广深打工,所以拥有更好的视野】这样的错觉
- 为啥工商银行的用户体验如此之差
- 汽车|看了中消协4S店服务测评调查结果,终于知道法系车为啥卖不好了
- 你为啥从窝窝商城离职?
- 为啥5G和2.4G默认的BSSID是相同的
- 为啥电器实体店的价格比淘宝贵那么多
- 现在在线学习视频有很多了,为啥大部分人还是喜欢下载下来观看
- 为啥到现在你还没有女朋友 ?
- 天赐的声音|33岁张雨绮为啥总离婚?看过这些照片就明白了,都是性感惹得祸
