java,php,go垃圾回收

java篇:

  java由于其比较特殊的内存分配结构, 对待gc也是非常认真, 提炼出了自己的方法。 (具体的清除方法会根据不同的区域,老年代,young代,堆区的其他地方 会采用不同的分代收集的方法)

   可达性分析:

       1.  可达性

            从GCroot(引用节点)节点出发进行遍历,只要从gcroot节点可达,则证明是非垃圾,  对于从gcroot节点达不到的,会标明可回收(但不会立刻回收), 会放入专门用于gc的队列中。

       其中只有满足下列条件之一的才可作为gcroot的节点:   虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(Native方法)引用的对象。

      以上,含有循环引用的节点不能作为gcroot节点的可达点,所以能被直接忽略。

      2.gc的队列处理

        在java的根类 Object中, 存在方法 finalize() 。 该方法会在进入gc队列中调用,来判断是否真的需要被回收。  

        可以通过重写finalize()方法,来与gcroot节点搭建可达性来避免一次(仅能一次)被回收的命运。(如果finalize执行时间过长会被强行中断,以防finalize中有死循环之类的问题)

        在队列中扫描,如果finalize()没有结果,或已经执行过一次finalize(),则会被直接回收。释放出对应的空间。

php篇:

    php主要以引用计数法为核心的gc手段, 但由于 无法解决循环引用的问题(例如 a和b两个对象 互相调用就会变成环状调用,导致内存泄漏) 。 所以在5.3中重新调整了gc的方法,增加了部分逻辑来针对上述问题。

     定义一个变量在底层会有引用记录(refcount), 每增加一个引用,refcount++;

   1. 深度优先遍历扫描所有的存储节点, 并且扫描过后的节点refcount--(学名为模拟删除), 并被标记(防止多次--)。   (如果refcount本身为0则直接标记回收)

   2.第二次遍历节点,

           2.1 if  refcount = 0则标记为可回收,放入对应的回收队列中。

           2.2     refcount > 0 则 refcount++(进行还原操作), 标记并放入新的缓冲区,待缓冲区满了之后进行3操作,去二次确认是否回收 (待缓冲区慢是怕多次调用gc算法影响性能)

   3. 遍历refcount > 0 的缓冲区队列,  针对其含有的所有引用进行refcount--; 

      if 减少后的refcount == 0 则说明   包含循环引用, 标记并准备回收。

      if 减少后的refcount > 0, 则进行还原操作, 认为暂时不可回收。

   eg: 数组a, a[0] = &a, a[1] = &a, 数组a循环调用自身(此时a的refcount为2)。  利用3所述, 对数组a的引用a[0],a[1]分别进行 refcount-1, 此时发现a的refcount 减少到0, 则标记循环引用, 进行清除操作;

  eg2: 对象a和b循环引用, a和b的refcount都为1,   对a的引用b做 refcount-1操作 , b中引用的a refcount-1 此时a和b的refcount都为0, 故为循环引用。。进行清除

  4.  php脚本执行完成后会回收对应的所有变量空间

 

go篇:

  go的gc从最初版本就不断在改变。

   最初版本的引用计数(如上所说,无法解决循环引用问题)

   1.3版本 修改为标记-清除。     - 有点像gcroot,从root节点扫描查找,  扫描不到的统一清除。 最大的问题是stw(stop the world), 使用标记-清除时 程序必须暂停。  当程序量不断扩大时, 此gc会引起系统暂停很久。

   1.5版本推出的三色法

          1. 默认所有节点都是白色, 从root节点扫描查找,将所有可达的标记为灰色,  放入灰色队列中

          2. 遍历灰色队列的每个节点, 将自身标记为黑色,并将所有的白色可达性节点标记为灰色, (广度优先遍历的思想)

          3. 调用2 直到灰色队列为空( 此时引用的都为黑色, 非引用的都为白色)

          4. 清除所有白色的节点,释放空间

          5. 将所有黑色节点还原回白色

        只需要在执行4和5的时候,暂停程序即可, 节省了停止程序的时间。 但面临的问题就是 在进行步骤2时, 尤其是黑色节点的引用在不断变化,会导致执行误清理和漏清理。

   1.8版本改进,在三色法的基础上加入了写屏障(wirte barrier), 在引用发生变化&&自身是黑色节点,  则将新的引用变为灰色加入灰色队列。  减少了误清理, 但还是会有漏清理的情况。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值