zoukankan      html  css  js  c++  java
  • GC算法-引用计数法

    概述

    引用计数法又是什么鬼呢? 顾名思义, 对对象的引用进行计数. 通过记录每个对象被引用的次数, 来确定这个对象是否可以被回收.

    实现

    首先, 对对象的引用数量进行管理, 什么时候会更新呢?

    1. 创建对象: 新建一个对象(对这个新的对象引用数量+1)
    2. 更新指针: 将一个指向A对象的指针重新指向B对象(将A对象引用数量-1, B对象引用数量+1)

    这次就不上代码了, 简单介绍一下思路就行. (我哥说代码看着费劲)

    前提: 我们有一个全局的空闲地址链表: FREE_HEAD

    创建对象的操作

    1. 从FREE_HEAD中寻找内存
    2. 若找到了, 该对象计数器置为1, 返回
    3. 若没有找到, 内存扩容, 返回1

    更新指针的操作

    1. 将新的对象引用计数+1
    2. 将旧的对象引用计数-1. 若-1后引用数量为0, 则将该对象及所有的子对象添加到FREE_HEAD链表中.

    实现说起来简简单单, 毕竟我也不用真的去实现, 简单想一下.

    分析

    在上一次的标记清除算法中, GC在每次内存不足时运行, 势必会导致程序暂停时间比较长. 但引用计数则在每次指针变更的同时进行管理, 在产生新的垃圾的时候立刻进行回收. 这就体现出它的几个优势了:

    1. 最大暂停时间短.
    2. 产生垃圾可立即回收

    当然, 只说优势不说劣势都是扯犊子. 首先, 引用计数的优势也会成为它的劣势, 计数频繁的计算, 会拖累程序的速度. 而且每个对象都要开拓空间来保存引用数量. 当然了, 还有经常被说到的循环引用的问题. 等等吧.

    1. 频繁的更新引用计数拖累程序速度
    2. 每个对象需要开拓额外空间保存引用计数
    3. 循环引用对象无法被回收(就是A引用B, B引用A. 但是他们都没有被其他对象引用, 导致他俩的引用始终为1, 无法回收)

    当然, 针对问题, 伟大的前人总是有办法去解决. 比如:

    延迟计数法: 针对频繁更新计数器的问题而提出的. 大概意思就是不去实时的对引用数量进行更新, 将引用数量为0的记录到一个待处理的链表中, 当需要新的内存时再统一处理. 但是这样又会增大暂停时间, 才不要.

    Sticky引用计数法: 引用计数通过额外的空间保存引用数量, 但这个必然会有最大值, 比如用1个字节, 则引用数量超过256的就记不下了. 这个方法对超出范围的处理方式很简单, 什么都不做, 不去回收, 毕竟被引用这么多次, 该对象定然很重要. 那这些对象不就永远都不能被回收了么? 可以, 等到没有内存了, 使用标记清除算法将所有对象过一遍.

    当然, 针对引用计数法还有很多演变, 有些还是很有意思的, 有些是我看不懂的.


    垃圾回收的整体思路分两个流派(我所知道的):

    1. 引用计数: 就是上面说的这种
    2. 可达性: 就是标记清除那种, 判断一个对象是否可以到达.

    引用计数的最大优势应该就是不需要暂停程序去进行回收了, 随使用随回收. 但劣势也很明显: 需要计数器额外空间以及循环引用的问题.

    个人是比较喜欢引用计数的, 实时性又高, 又不需要太多的额外空间. 只是需要在编写代码的时候刻意规避循环引用, 或者其他方法规避一下? 甚至不去处理都刻意, 如果只有少数的话(如果有很多, 还是换个算法吧).

  • 相关阅读:
    二叉树
    bfs
    E-Gold Coins
    D-We Love MOE Girls
    A
    哈希--查找出现过的数字
    二分查找
    KMP简单应用
    KMP算法(2)
    [JSOI2008]最大数
  • 原文地址:https://www.cnblogs.com/hujingnb/p/12638443.html
Copyright © 2011-2022 走看看