自动内存管理

自动内存管理(Automatic Memory Management)是很多现代程序语言提供的功能之一。自动内存管理通常包含两个部分:一是分配,而是回收;之所以称之为自动,是因为在这些语言中无需程序员手动显式地申请或释放内存。

比如在 C 语言中,你必须保证 malloc 和 free 是成对出现的,而由于这一切都是手动进行,那么就有可能出现问题。比如申请了内存却忘记了释放,会造成内存泄漏,而且会严重影响程序性能,因为内存管理器的管理压力很大,寻找适合大小的内存时会消耗更长时间;而且积累到一定程度之后会导致程序崩溃。而过早释放了内存,则会导致悬挂指针,而悬挂指针导致的崩溃可能会更诡异,在使用一个悬挂指针时,它指向的内存空间可能已经归还给了操作系统,可能已经被清空,更有可能已经被其他程序所使用,在这种情况下,程序的崩溃可能不会立即发生,更增加了查找问题的难度。

除了 C 语言这种直接手动显示申请和释放内存的语言之外,还有一些语言通过别的手段实现了内存的安全回收,比较新的比如 Rust 语言引入的所有权,使得代码在编译时即可被编译器自动完成正确的内存申请与释放功能。

自动内存管理在一定程度上可以解决大多数的内存泄漏和悬挂指针问题。自动内存管理引入垃圾回收机制来使得程序员无需再手动进行内存管理,成熟的垃圾回收算法能够阻止内存泄漏的发生;而且,由于释放内存也是由自动内存管理来完成,也就不会出现二次释放之类的事故,也避免了悬挂指针的问题。

常见的垃圾回收机制有以下几种:

  • 引用计数法:比如 PHP 语言使用的就是引用计数法,在 5.3 版本之前,引用计数法无法处理循环引用,而有可能导致内存泄漏; 5.3 版本之后,PHP 核心团队增强了引用计数法,在此基础上采用同步周期回收的同步算法来处理了此问题。
  • 标记清除法:比如 Java 8 中老年代的 CMS 垃圾回收器,其算法就是标记清除,优点是速度快,程序暂停的时间短,但缺点也很明显:内存碎片化严重。Go 语言中的回收算法是增强的标记清除法。
  • 标记整理法:比如 Java 8 中的 Parallel Scavenge 收集器,其在老年代的回收算法就是标记整理,其步骤与标记清除大致相似,只是最后清除垃圾前进行了整理,然后一并清除。
  • 复制法:比如 Java 中的新生代的大部分收集器,都采用的复制算法,优点是快,缺点是需要两倍的空间(一半使用,一半用于复制)。

最后更新: