一、垃圾回收
垃圾回收,指的是可回收的内存的回收。理论上讲,可回收的内存应该尽快回收。在软件运行过程中,经常会申请分配内存,用完后,就会把内存释放。在一些语言上如C/C++这类语言上,需要手动进行内存的释放,它既带来了高效率但也引进了不安全。在后面的一些新兴语言如Java、Go等语言中,引入了GC,即垃圾回收机制。GC会通过算法通过一系列的手段把应用程序不再使用的内存自动回收。
二、主要原理
垃圾回收的原理比较清晰,一般来说,计算机的内存主要是指堆和栈。诸如几级缓存、寄存器等等此类存储一般很小,不在此讨论范围之内。而在堆和栈中,栈一般是计算机本身来管理,或者说操作系统自己来管理。麻烦之处,就在于堆,或者从某种意义上来讲,所谓的GC,重点是指堆的内存管理。
堆内存是什么?堆其实就是动态分配的内存空间。一般来说,堆的内存相对来说很大。对于一些特别大的内存申请,如1G以上的,有些内存回收器给出了独立的内存管理机制,这里也不对此展开。只要掌握了普通堆内存的GC机制,再看其它内存的管理回收机制,基本就都好理解了。
为了能更好的回收内存,GC首先要对内存的分配和管理有一个方式。
首先,在内存对象的管理上,要分为活动和非活动两类对象,对判断为非活动的对象,就可以在适当的时机进行内存的回收;
第二,内存要有一个管理的数据结构,一般是树的形式来管理,可以通过根结点来查找所有的内存对象;
第三,内存的分配一定要分块,不同的大小的内存有不同的大小内存块来对应,尽量减少内存的GC和管理的方便。其实分块就和OS中分页和分段原理一样,容易管理且减少内存碎片,至于是叫块还是叫孔,叫线,叫回收区,叫啥,那是另外一回事儿。
第四,内存分配有一个管理机制,即能够查找内存的位置、指定内存的状态和进一步处理的信息。换句话说要有一个管理器。
第五,内存的垃圾判定回收要有一个或者多个算法。
通过上述的原理描述,基本就可以对照当前主流的GC算法,比如c++的智能指针,其实就是用引用计数来判断对象内存的使用状态;JAVA等语言则是通过标记再加后续的各种处理机制,来判断内存是否回收。诸如此类。
说得直白一些,GC就是通过技术手段实现对内存的应用状态判断,并在此基础上,进行快速的内存回收并尽量消除内存碎片。
三、评价标准
GC的方式有很多种,但哪种好呢?所以就得有一个评定的标准:
1、最直接的评定标准就是快。快就意味着吞吐量要大。
2、除了快以外,在最坏的情况下,也要好用,也就是最大暂停时间。
3、内存应用要有效率,不能因为GC就浪费更多的内存。
4、内存访问的局部性。这个其实和计算机的局部性原理一样,内存访问越集中,内存GC越容易管理,效率就越高。碎片也就越少。
上述的几个标准,尤如很多不可能三角一样,往往也是不可兼得的。如果要想更准确判断内存状态,提高速度,就需要引入更多的辅助内存空间,而这样往往浪费了很多的内存。如果想减少内存碎片,就需要移动使用内存,而这不但需要额外空间,还需要增加搜索次数。以上种种,所有的GC算法无不在此上面进行各种取舍。
四、总结
GC机制,从目前看来,应该是所有语言向前发展的一个重要方向。包括C/c++这些语言都有意无意的在增加相关的属性。更惶论现在的Go、Python等语言。包括目前很热门的Rust虽然没有明确提出GC,但其相关的设计,其实也有GC的影子。其实所有的GC,就是对资源的一种管理,只是内存目前在计算机中最典型,最突出,所以GC就首先出现在这里。以后如果再出现一些其它资源也这么迫切,同样会有它们的GC出现。
GC其实就是对内存资源的一种控制,一个管理机制或者说一种算法。这才是根本。