Python技术迷

面试官:Python是如何实现内存管理的?

大家好,我是虎哥。

今天要和大家聊聊Python的内存管理。作为一个资深Python开发工程师,我觉得这其实是个展示技术的好机会——面试官一问,你可以先微微一笑,丢回一个问题:“您说的是官方的CPython解释器吗?”这是个小技巧,能直接展示出你对Python不同解释器的了解,先别管面试官自己知不知道CPython和别的解释器有啥区别,这自信得有。

那么,Python到底是如何处理内存管理的呢?用咱们程序员的话来说,Python的内存管理机制其实就是——“你写代码就行,内存我来管”。

换句话说,在Python中,内存空间的分配和释放是自动化的,这是由Python解释器在运行时动态进行的。这样的设计不仅省了开发人员的事儿,还能在一定程度上帮我们减少内存泄漏问题。

好啦,废话不多说,接下来就以CPython解释器为例,看Python内存管理的几个关键“武器”吧。

首先, 引用计数 就是CPython最基础的内存管理机制。说白了,Python里的每一个对象其实都是一个结构体,比如我们常见的 PyObject ,这个结构体里有一个 ob_refcnt 的成员变量,专门用来计数有多少个地方引用了这个对象。 代码里一旦创建了一个对象,引用计数就加1;如果有个新变量引用它,比如赋值给另一个变量,计数也会加1;要是把它作为参数传到函数里,引用计数还是加1。删除呢?也简单,你写个 del 把这个引用删了,或者让引用重新指向其他对象,引用计数就会减1。
import sys

a = [1, 2, 3]
print(sys.getrefcount(a))  # 查看引用计数
执行这段代码,你会发现 sys.getrefcount(a) 的结果比预想的多了1,这其实是因为 getrefcount 函数调用时自己也增加了一个临时引用,这说明引用计数机制确实实时跟踪对象引用的变化。

这么做虽然自动化,但也不是完美的——引用计数对循环引用的情况可无能为力。你如果写个“左手倒右手”的循环引用,引用计数永远不会降到0,这就麻烦了。

那么, 标记清理 (Mark and Sweep)算法在这时就登场了,用来解决循环引用的问题。这套算法的核心思想是“标记+清理”,听起来有点中二哈?其实就是,Python会遍历所有对象,把可达对象标记出来,接着再扫描一遍,凡是没有标记为可达的,就收拾掉。 CPython底层维护了两个双端链表,链表A用来存放需要扫描的容器对象,链表B存放临时不可达的对象。链表A的节点有个 gc_ref 变量,这个变量初始值等于引用计数。 当清理开始,A链表里的对象会把自己所引用对象的 gc_ref 减1,如果减完之后某个对象的 gc_ref 为0,就会被标记为“暂时不可达”并移动到链表B中;若不是0,则递归标记该对象的引用为可达。最终链表B中那些“孤独”的对象就被直接回收。 然后,我们来聊聊CPython垃圾回收系统中的“特级加速器”—— 分代回收 (Generational GC)。Python的思路是这样的:“对象活得越久,成垃圾的概率越低。”因此,Python把对象划分为三代,分别是第0代、第1代和第2代,代表对象的“年龄”。

一个新创建的对象从第0代起步,每次在垃圾回收中幸存下来就升级一代。不同代的对象回收频率不同,0代回收最频繁,2代回收最少。为什么这么做呢?因为一个对象活得时间越长,它通常就是“靠谱”的,所以就不急着回收,免得浪费资源。

为了实现这一点,Python的垃圾回收模块( gc )设置了一个“门槛”系统,每个代的垃圾回收频率由内存分配次数来决定。比如,你可以通过 gc.get_threshold() 来查看不同代的门限值:
import gc

print(gc.get_threshold())  # 返回一个三元组 (700, 10, 10)
这个返回值的意思是:每进行700次内存分配操作后,Python会触发一次0代垃圾回收;每进行10次0代垃圾回收后会触发一次1代垃圾回收;每进行10次1代垃圾回收后会触发一次2代垃圾回收。你甚至可以用 gc.set_threshold() 调整这几个门槛。
gc.set_threshold(750, 15, 15)  # 调整门限

当然,门槛设太低也不好,频繁回收不仅效率低,还会导致性能下降,内存使用也不一定优化。合理的回收机制设置既能优化内存占用,也能保持代码的执行效率。

好,回到最初的问题,如果面试官直接问你“Python是如何实现内存管理的?”你可以这样回答:“Python通过引用计数、标记清理和分代回收来管理内存。引用计数是基础,但无法处理循环引用,因此Python还使用了标记清理算法。为了提高垃圾回收效率,Python又加入了分代回收机制,优先清理新生成的短命对象。”

对编程、职场感兴趣的同学,大家可以联系我微信: golang404 ,拉你进入“程序员交流群”。
🔥 虎哥私藏精品 热门推荐 🔥 虎哥作为一名老码农,整理了全网最全 《python高级架构师资料合集》 。
资料包含了 《IDEA视频教程》 、 《最全python面试题库》 、 《最全项目实战源码及视频》 及 《毕业设计系统源码》 ,总量高达 650GB 。 全部 免费领取 !全面满足各个阶段程序员的学习需求 。