Просмотр исходного кода

feat: 完善 Sticky引用计数法

liucong5 2 лет назад
Родитель
Сommit
64c7eda331
1 измененных файлов с 21 добавлено и 3 удалено
  1. 21 3
      垃圾回收/README.md

+ 21 - 3
垃圾回收/README.md

@@ -446,9 +446,10 @@ dec_ref_cnt(obj) {
 
 - **优点**
 
-1. 可立即回收垃圾,每个对象始终知道自己的被引用数,当引用数归零自己就把自己回收了
+1. 可立即回收垃圾,每个对象始终知道自己的被引用数,当引用数归零自己就把自己回收了
 2. 最大暂停时间短,只有通过 mutator 更新指针时程序才会执行垃圾回收
 3. 没有必要沿着指针查找,与 标记清除 不同,引用计数 无需由根沿指针查找
+4. 内存碎片少,在引用计数算法中,由于对象在不再被使用时就立即被释放,所以内存的分配和释放更加均匀,不太可能在内存中形成大的空洞
 
 - **缺点**
 
@@ -459,6 +460,14 @@ dec_ref_cnt(obj) {
 
 ### 延迟引用计数法
 
+引用计数算法中 **计数器值的增减处理繁重**
+
+- 频繁更新:在一个动态变化的系统中,对象间的引用关系可能会频繁改变,这就导致需要频繁地更新引用计数。每次引用的创建、删除或者修改都可能需要修改计数器的值
+- 同步开销:在多线程环境中,为了保证引用计数的正确性,可能需要使用锁或者其他同步机制来保护计数器,以防止并发的引用修改导致计数错误。这会增加额外的同步开销 
+- 内存开销:每个对象都需要一个额外的计数器来存储引用计数,这会增加内存开销
+
+
+
 ### Sticky引用计数法
 
 在 引用计数 中,需要考虑为 计数器 设置多大的位宽
@@ -469,7 +478,7 @@ dec_ref_cnt(obj) {
 
 假设计数器的位宽为5位,那么最多只能数到 2的5次方减1,也就是31个引用计数。如果对象被大于31个对象引用,那么计数器就会溢出,针对溢出有2种解决方式
 
-1. 什么都不做
+1. **什么都不做**
 
 对于计数器溢出的对象,我们可以不再增减其计数器的值,也不销毁这个对象,就让他占用内存空间
 
@@ -479,9 +488,18 @@ dec_ref_cnt(obj) {
 
 考虑到上面的两点,对于计数器溢出的对象,什么都不做也不是不行
 
-2. 使用 GC标记-清除算法 进行管理
+2. **使用 GC标记-清除算法 进行管理**
+
+- 引用计数: 首要的垃圾回收策略是引用计数,这意味着每当一个对象被创建或引用时,它的引用计数都会增加。反之,每当一个引用被删除或离开作用域,引用计数就会减少
+- 立即回收: 当一个对象的引用计数变为0时,说明没有任何引用指向它,垃圾回收器会立即回收它,释放其占用的内存
+- 检测循环引用: 然而,引用计数算法无法处理循环引用的问题。当垃圾收集器发现内存消耗增加或者在适当的时间(例如低负载时),它会启动标记-清除算法
+- 重置引用计数: 标记-清除结束后,所有活动对象的引用计数被重置(设为0)
+- 标记: 在标记阶段,垃圾收集器从根对象开始,遍历所有可达对象,并将它们标记为活动,对其计数器进行增量操作。这个过程会找出所有的活动对象,包括被循环引用的对象
+- 清除: 在清除阶段,垃圾收集器遍历所有的对象,清除那些没有被标记或者计数器值为0的对象,也就是那些不可达的对象,包括被循环引用的对象
 
+通过上面的几个步骤,将 引用计数算法和GC标记清除算法 结合起来,在计数器移除后即使对象成了垃圾,程序还是可以回收它
 
+另外,这种结合起来的方法可以解决循环引用的问题
 
 ### 1位引用计数法