Garbage Collection
在编程语言中,垃圾回收(Garbage Collection, GC) 是一种自动内存管理算法,垃圾回收器(Garbage Collector) 是其实现,负责将程序已不再使用的内存回收再利用。
美国计算机科学家 John McCarthy 于 1959 年给 Lisp 语言首次引入。
通常内存管理分为手动内存管理和自动内存管理两类,手动内存管理指程序员主动控制对象的创建和释放的全过程,其包含 rust 这种所有权特殊类型;自动内存管理就是指垃圾回收实现。
垃圾回收策略
跟踪回收
跟踪回收(tracing) 是最常用的垃圾回收策略,这种算法定期遍历其管理的内存,从若干 根对象(roots) 开始 扫描(scanning),查找与之相关的对象,然后标记其余没有关联的对象,最后回收这些没有关联的对象占用的内存空间。
标记 - 回收的行为可以被细分为不同的实现。
标记 - 清除算法
标记 - 清除(Mark-Sweep) 先暂停整个程序的全部运行线程(Stop the world,STW),让回收线程以单线程进行扫描标记,并进行直接清除回收,然后回收完成后,恢复运行线程。這樣会产生大量的空闲空间碎片,和使大容量对象不容易获得连续的内存空间,而造成空间浪费。
标记 - 压缩算法
和“标记-清除”相似,不同的是,回收期间同时会将保留的存储对象搬运汇集到连续的内存空间,从而整合空闲空间,避免内存碎片化。
停止 - 复制算法
需要程序将所拥有的内存空间分成两个部分。程序运行所需的存储对象先存储在其中一个分区(定义为“分区 0”)。同样暂停整个程序的全部运行线程,进行标记后,回收期间将保留的存储对象搬运汇集到另一个分区(定义为“分区 1”),完成回收,程序在本次回收后将接下来产生的存储对象会存储到“分区 1”。在下一次回收时,两个分区的角色对调。
引用计数回收
引用计数回收(reference counting) 是最早也最简单的垃圾回收策略,其为每一个对象都设置一个引用计数器,当其他对象引用这个对象时计数器加一,反之计数器减一。当引用计数器为零时该对象被销毁内存回收。
引用计数回收有个相同于手动内存管理,不同于跟踪回收的特点,其保证对象在最后一个引用被销毁后立即被回收,而且通常只访问 CPU 缓存中、待释放对象中或直接被这些对象指向的内存,因此不会对 CPU 的缓存和虚拟内存操作产生显著的负面影响。
当然也有很多缺点:
- 循环引用无法释放
- 额外存储空间(引用计数器)
- 额外计算开销(引用计数器加减)
- 原子操作需求(多线程的引用计数器)
- 非实时:某个超大递归对象的释放会导致当前线程阻塞,因此可以将回收步骤放到单独线程进行,这需要额外的开销
In computer science, garbage collection (GC) is a form of automatic memory management. The garbage collector attempts to reclaim memory that was allocated by the program, but is no longer referenced; such memory is called garbage. Garbage collection was invented by American computer scientist John McCarthy around 1959 to simplify manual memory management in Lisp.
Garbage collection relieves the programmer from doing manual memory management, where the programmer specifies what objects to de-allocate and return to the memory system and when to do so.[1]
Other, similar techniques include stack allocation, region inference, and memory ownership, and combinations thereof. Garbage collection may take a significant proportion of a program's total processing time, and affect performance as a result.[1:1]
- Tracing
- Reference counting