垃圾回收算法

垃圾回收算法(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虚拟机》

posted @   kaleidopink  阅读(160)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示