Python的内存管理
Python 的内存管理和存储机制与 C++ 有很大的不同,它更高级,主要依赖于 Python 解释器和垃圾回收机制来管理内存。
1. 堆和栈
Python 中的栈主要用于管理函数调用和局部变量,而堆用于动态分配对象。
- 栈:用于管理函数调用的上下文,包括局部变量、参数和返回地址等。
- 堆:用于存储所有动态分配的对象,包括变量、数据结构(如列表、字典等)。Python 的对象通常是通过
malloc
等底层机制分配在堆上。
2. 对象管理和引用计数
Python 采用引用计数(Reference Counting)来管理内存。每个对象都有一个引用计数,当对象被引用时,计数加一,当引用被删除时,计数减一。
- 引用计数:
- 每个对象都包含一个引用计数器,记录有多少引用指向该对象。
- 当引用计数变为零时,对象的内存就会被释放。
例子: python a = [1, 2, 3] # 创建一个列表对象,引用计数为 1 b = a # 引用计数增加到 2 del a # 引用计数减少到 1 del b # 引用计数减少到 0,对象被垃圾回收
3. 垃圾回收
虽然引用计数是主要的内存管理方式,但它无法解决循环引用的问题(即两个或多个对象相互引用,导致引用计数永远不为零)。为了解决这一问题,Python 引入了垃圾回收(Garbage Collection,GC)机制。
- 标记-清除(Mark-and-Sweep):
-
Python 的垃圾回收器会定期检查对象图,标记活动对象并清除未被引用的对象。
-
分代收集(Generational Collection):
- Python 将对象分为不同的代(generations),年轻代对象更频繁地进行垃圾回收,而老年代对象较少进行回收。
- 这种策略基于“新生对象更可能被快速回收”的假设,能够提高垃圾回收的效率。
4. 内存池(Memory Pool)
Python 使用内存池技术来管理小对象的分配和释放,以提高内存分配的效率。
- 小对象分配器:
-
小对象(大小小于 256 字节)使用专用的内存池进行分配。这些内存池由 Python 的内存管理器管理,避免了频繁调用系统的内存分配函数。
-
大对象分配:
- 大对象则直接向操作系统申请内存。
5. PyObject 结构
Python 中的每个对象都是 PyObject
结构的实例。这个结构包含了引用计数和类型信息。
PyObject
结构:- 每个对象都有一个引用计数(ob_refcnt)和一个指向类型对象的指针(ob_type)。
c typedef struct _object { int ob_refcnt; // 引用计数 struct _typeobject *ob_type; // 类型指针 } PyObject;
示例说明
Python 中内存管理的简单示例:
import sys
a = [1, 2, 3] # 创建一个列表对象
print(sys.getrefcount(a)) # 输出 2,因为 sys.getrefcount 也会创建一个临时引用
b = a # b 引用了 a
print(sys.getrefcount(a)) # 输出 3
del a # 删除一个引用
print(sys.getrefcount(b)) # 输出 2
del b # 删除最后一个引用,对象被垃圾回收