zoukankan      html  css  js  c++  java
  • 垃圾回收算法

    垃圾回收算法(garbage collection,以python为例)

    自动内存管理是很多或者说大部分编程语言所具有的特性,一般只有C/C++家族为了追求性能而选择了手动内存管理。

    所谓内存管理,一般是指堆区的内存管理。栈区的变量会随着工作区的改变而释放掉。

    引用计数

    引用计数是GC中实现起来最简单的一类算法,CPython虚拟机以及swift里都使用了引用计数法。

    决定一个变量所指向的内存是垃圾还是有用的数据,在于是否被其它变量所引用。

    如:

    objA = A();
    objB = objA;
    

    这样A对应的内存就有两个引用。只有objA和objB都指向其它内存并且没有新的引用的情况下,A对应的内存才会称为垃圾内存,需要被回收。

    因此当一个变量改变引用的时候需要完成以下工作:

    1. 新的内存增加一个引用
    2. 原来的内存减小一个引用
    3. 判断原来的内存是否为零引用,如果是,进行内存回收

    引用计数优点:

    1. 垃圾内存可以立即得到回收
      为什么说可以立即回收是优点看到另一种GC算法就明白了。
    2. 没有暂停时间
      不需要设置一个专门的GC线程进行内存回收,业务线程就可以自己搞定。

    缺点:

    1. 每次对象引用的改变都变得非常费时。
    2. 最致命的缺点是无法回收循环引用的内存。
      一般循环引用的内存都是垃圾内存,但是每个变量的引用又不为零,所以导致内存泄露。

    Training GC

    Training GC学习需要有一定的图论知识,如果不具备请事先补充

    Training GC算法是一种追踪算法。在当前程序中,所有的变量其实可以看成一个图。

    将所有不在堆中定义但是指向堆内存的变量称为roots,如果从roots可以到达某个对象,则该对象是被引用的。否则就是属于垃圾内存。

    判断roots是否可以到达某个对象,就需要使用深度优先搜索或者广度优先搜索来实现。

    内存回收

    Training GC可以找到是否需要回收的内存,那怎么样具体回收内存呢?

    Mark-sweep方法

    在使用Training GC时,将所有的可达对象都mark。然后遍历所有的对象,将没有被mark的对象加入到一个链表freelist中。如果新加入的回收对象的内存地址与freelist的最后一个chunk相邻,则直接扩容最后一个chunk,不需要新加入chunk。

    这个链表代表了可以被任意使用的内存,最好可以将链表内的内存按大小进行排序。

    当需要新分配一块内存时,可以遍历freelist,找到一块刚好适合的内存块chunk分配给新对象。

    这个操作和操作系统内部内存分配的方式非常相似。

    copy GC方法

    mark-sweep方法虽然方便,但是存在使内存碎片化的缺点。分配内存的效率低下更不用说。

    相比之下,copy GC使用内存池的思想。事先开辟一大块内存,将该内存分为两块。

    每次分配内存都只在其中一块进行,当其中一块内存达到某个threshold时。通过Training GC找到所有可达对象,然后将所有可达对象都copy到另一块内存中。而垃圾内存对象都留在了原内存中被看成了可以被任意分配的对象。这样就达到了垃圾回收的目的。

    copy GC的缺点是存在内存浪费,任意时刻都只有一半以下的内存被使用。且每次垃圾回收都需要暂停程序运行来进行数据copy。

    参考文献

    [1] 海纳 《自己动手写Python虚拟机》

    我愿潇洒如鹰,远离地上宿命
  • 相关阅读:
    BZOJ4036 HAOI2015按位或(概率期望+容斥原理)
    洛谷p2661信息传递题解
    洛谷P1434滑雪题解及记忆化搜索的基本步骤
    二分图最大匹配
    线段树

    图论基本算法
    并查集
    RMQ--ST表
    矩阵快速幂和矩阵乘法
  • 原文地址:https://www.cnblogs.com/lunar-ubuntu/p/13534532.html
Copyright © 2011-2022 走看看