垃圾回收算法
垃圾回收算法(garbage collection,以python为例)
自动内存管理是很多或者说大部分编程语言所具有的特性,一般只有C/C++家族为了追求性能而选择了手动内存管理。
所谓内存管理,一般是指堆区的内存管理。栈区的变量会随着工作区的改变而释放掉。
引用计数
引用计数是GC中实现起来最简单的一类算法,CPython虚拟机以及swift里都使用了引用计数法。
决定一个变量所指向的内存是垃圾还是有用的数据,在于是否被其它变量所引用。
如:
objA = A();
objB = objA;
这样A对应的内存就有两个引用。只有objA和objB都指向其它内存并且没有新的引用的情况下,A对应的内存才会称为垃圾内存,需要被回收。
因此当一个变量改变引用的时候需要完成以下工作:
- 新的内存增加一个引用
- 原来的内存减小一个引用
- 判断原来的内存是否为零引用,如果是,进行内存回收
引用计数优点:
- 垃圾内存可以立即得到回收
为什么说可以立即回收是优点看到另一种GC算法就明白了。 - 没有暂停时间
不需要设置一个专门的GC线程进行内存回收,业务线程就可以自己搞定。
缺点:
- 每次对象引用的改变都变得非常费时。
- 最致命的缺点是无法回收循环引用的内存。
一般循环引用的内存都是垃圾内存,但是每个变量的引用又不为零,所以导致内存泄露。
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虚拟机》
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 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)