跳到主要内容

如何在 Python 中管理内存?

Python 内存管理机制​

Python 的内存管理由解释器自动处理,核心机制有三层:

① 引用计数(Reference Counting) ← 主要机制
② 垃圾回收(Garbage Collection) ← 处理循环引用
③ 内存池(Memory Pool) ← 小对象复用,提升性能

① 引用计数​

每个对象都维护一个引用计数器,当计数降为 0 时立即释放内存。

import sys

a = [1, 2, 3]
print(sys.getrefcount(a)) # 2(a 本身 + getrefcount 的参数)

b = a # 引用计数 +1
print(sys.getrefcount(a)) # 3

del b # 引用计数 -1
print(sys.getrefcount(a)) # 2

del a # 引用计数降为 0,内存释放

引用计数增加的场景:赋值、传参、添加到容器、sys.getrefcount() 调用本身。

② 垃圾回收:处理循环引用​

引用计数无法处理循环引用(两个对象互相引用,计数永不为 0):

import gc

class Node:
def __init__(self):
self.ref = None

a = Node()
b = Node()
a.ref = b # a 引用 b
b.ref = a # b 引用 a

del a
del b
# 此时 a、b 引用计数均为 1,不会被引用计数释放
# Python 的分代垃圾回收器会检测并清理

Python 使用分代垃圾回收(Generational GC),将对象分为三代:

代含义触发频率
第 0 代新创建的对象最频繁
第 1 代经历过一次 GC 的对象中等
第 2 代长期存活的对象最少
import gc

gc.collect() # 手动触发垃圾回收
print(gc.get_count()) # (第0代, 第1代, 第2代) 对象数量
print(gc.get_threshold()) # (700, 10, 10) 触发阈值

gc.disable() # 禁用 GC(极少数高性能场景)
gc.enable() # 重新启用

③ 内存池(pymalloc)​

CPython 对小于 512 字节的对象使用内存池(pymalloc),避免频繁向操作系统申请/释放内存:

  • 小整数(-5 ~ 256)全局缓存,永久复用
  • 短字符串驻留(interning),同值共享同一对象
  • 内存池按块分配,释放后归还池中而非操作系统
# 小整数缓存
a = 100
b = 100
print(a is b) # True ← 同一个缓存对象

a = 1000
b = 1000
print(a is b) # False ← 超出缓存范围

内存管理最佳实践​

1. 用 with 语句及时释放资源​

# ✅ 推荐:with 块结束自动关闭文件,释放文件描述符
with open("data.txt") as f:
data = f.read()

# ❌ 不推荐:依赖 GC 释放
f = open("data.txt")
data = f.read()
# 忘记调用 f.close()

2. 处理大数据用生成器替代列表​

# ❌ 一次性加载到内存
data = [process(line) for line in open("huge.log")]

# ✅ 惰性处理,内存占用固定
def process_lines(path):
with open(path) as f:
for line in f:
yield process(line)

3. 用 __slots__ 减少实例内存占用​

class WithDict:
def __init__(self, x, y):
self.x = x
self.y = y

class WithSlots:
__slots__ = ["x", "y"] # 禁用 __dict__,改用固定数组
def __init__(self, x, y):
self.x = x
self.y = y

import sys
print(sys.getsizeof(WithDict(1, 2))) # ~48 字节(+ __dict__ ~232 字节)
print(sys.getsizeof(WithSlots(1, 2))) # ~56 字节(无 __dict__)

4. 显式删除不再需要的大对象​

import gc

big_data = load_large_dataset()
process(big_data)

del big_data # 显式删除
gc.collect() # 必要时手动触发 GC

5. 使用 weakref 避免循环引用​

import weakref

class Parent:
def __init__(self):
self.child = None

class Child:
def __init__(self, parent):
self.parent = weakref.ref(parent) # 弱引用,不增加引用计数

p = Parent()
c = Child(p)
p.child = c
# 删除 p 时不会产生循环引用问题

内存分析工具​

# 查看对象引用计数
import sys
sys.getrefcount(obj)

# 查看对象内存大小(不含子对象)
sys.getsizeof(obj)

# 查看所有存活对象
import gc
gc.get_objects()

# 第三方工具:内存详细分析
# pip install memory-profiler
# @profile 装饰器逐行分析内存

总结​

机制作用触发时机
引用计数对象归零立即回收自动、实时
分代 GC回收循环引用阈值触发或手动
内存池小对象高效复用自动、透明
  • Python 内存管理基本全自动,日常开发无需手动干预
  • 大内存场景:优先使用生成器、__slots__、weakref
  • 有内存泄漏嫌疑时:用 gc 模块和 memory-profiler 定位