python内存管理核心是引用计数,对象引用归零时立即释放内存,确保高效即时回收;2. 循环引用由分代垃圾回收器解决,gc通过标记-清除算法识别并清理不可达的循环引用孤岛;3. cpython对小对象使用内存池(pymalloc)策略,减少系统调用和碎片化,提升分配效率,大对象则直接由操作系统管理,整体机制保障了自动、高效、低开销的内存管理。

Python的内存管理机制,说白了,核心就是一套巧妙的组合拳:引用计数作为主力,配合一个专门处理循环引用的垃圾回收器。这套机制保证了我们写代码时,多数情况下不用操心内存的分配与回收,因为它在底层已经默默地把脏活累活都干了。当然,CPython作为最常用的实现,还有它自己一套针对小对象的内存池策略,这大大提升了效率。

当我们谈论Python的内存管理,首先想到的就是引用计数。在CPython的源码里,每个Python对象都有一个
ob_refcnt
ob_refcnt
但引用计数有个天生的“盲点”:循环引用。试想一下,对象A引用了B,B又引用了A,即使外部已经没有对A和B的引用,它们的
ob_refcnt
立即学习“Python免费学习笔记(深入)”;

除了引用计数和垃圾回收,CPython在内存分配上也有自己的优化。对于频繁创建和销毁的小对象(比如整数、浮点数、字符串等),CPython不会每次都向操作系统申请内存。它维护了一个内存池(或称竞技场、pymalloc
malloc
free
Python内存管理的核心机制,毋庸置疑,就是引用计数。每个Python对象内部都有一个
ob_refcnt

引用计数虽然高效,但它有一个致命的弱点:无法处理循环引用。想象一下,两个对象A和B,A引用了B,B又引用了A,即使没有任何外部变量再引用A或B,它们的引用计数永远不会降到零,因为它们彼此“依赖”。这就导致了内存泄漏。为了解决这个问题,Python引入了垃圾回收器(Garbage Collector, GC)。这个GC不是实时运行的,它会周期性地启动,专门寻找那些引用计数不为零,但实际上已经无法从程序“根”访问到的对象集合。
CPython的GC采用的是分代回收(Generational Collection)策略。它将所有可回收的对象分为三代:0代、1代、2代。新创建的对象都在0代。每次GC运行时,会优先扫描0代对象。如果一个0代对象在一次或几次GC扫描后依然“存活”(即它的引用计数不为零,且可能参与了循环引用),它就会被提升到1代。同理,1代的对象在经历更多次GC后,如果仍存活,就会被提升到2代。这种分代的设计是基于一个经验事实:绝大多数对象的生命周期都很短。因此,频繁地扫描新对象(0代)可以高效地回收大部分垃圾,而对老对象(1代、2代)的扫描频率则可以大大降低,从而减少GC对程序性能的影响。
GC识别循环引用的过程大致是这样的:它会从所有“根”对象(比如全局变量、调用栈中的局部变量)开始,遍历所有可达的对象,并把它们标记起来。然后,GC会检查那些引用计数不为零但未被标记的对象。这些未被标记的对象就是循环引用的“孤岛”,因为它们虽然有引用,但已经无法从程序的任何活的部分访问到。一旦发现这样的循环,GC就会“断开”它们之间的引用,然后将其内存释放。你也可以通过
import gc
gc.collect()
import gc
class Node:
def __init__(self, name):
self.name = name
self.next = None
# 创建循环引用
node1 = Node("A")
node2 = Node("B")
node1.next = node2
node2.next = node1
# 此时外部对node1和node2有引用,引用计数不为0
# 解除外部引用
del node1
del node2
# 此时,node1和node2指向的对象虽然外部引用没了,但它们内部互相引用,引用计数不为0
# 它们会形成一个无法被引用计数回收的循环
# 强制执行垃圾回收
gc.collect()
# 此时,如果这些对象是可回收的,它们就会被GC清理掉
# 实际效果可以通过gc.get_objects() 或 sys.getrefcount() 结合调试观察CPython在内存分配上,其实做了一层精巧的优化,这主要体现在对小对象的处理上。它并不是每次需要内存都直接向操作系统(OS)请求
malloc
pymalloc
这套系统主要针对那些大小固定且频繁创建和销毁的小对象,比如小整数、短字符串、元组、字典等。它的核心思想是维护一个内存池(memory pool)。这个内存池由一系列arena(竞技场,通常是256KB的内存块,直接从OS申请)组成。每个arena又被细分成多个pool,每个pool专门用于存储特定大小的对象。例如,一个pool可能只存储16字节的对象,另一个可能只存储32字节的对象。
当Python需要创建一个小对象时,它会首先检查对应的pool是否有空闲的内存块。如果有,就直接从pool中快速分配。当这个小对象被回收时,它的内存块不会立即归还给操作系统,而是被标记为“空闲”,回到它所属的pool中,等待下次被复用。这种机制带来了显著的性能提升:
malloc
free
对于大对象(通常是那些大小超过512字节的对象,这个阈值可能会根据版本有所调整),CPython则直接退化到使用操作系统的
malloc
free
所以,CPython的内存分配策略是一个分层的、优化的设计:对小对象进行精细化管理以提高性能和内存利用率,对大对象则直接依赖底层操作系统。这使得Python在处理各种规模的数据和应用时,都能保持不错的内存效率。
以上就是Python源码中的内存管理机制 探索Python源码自动回收原理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号