内存优化
问题
Python 程序占用内存过多怎么优化?有哪些内存分析工具?
答案
常用优化手段
1. __slots__ 减少实例内存:
import sys
class WithDict:
def __init__(self, x, y):
self.x = x
self.y = y
class WithSlots:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
print(sys.getsizeof(WithDict(1, 2).__dict__)) # 104 bytes
# WithSlots 没有 __dict__,节省约 40%
2. 生成器替代列表:
# ❌ 大列表
data = [process(x) for x in range(10_000_000)] # 可能占用 GB 级内存
# ✅ 生成器
data = (process(x) for x in range(10_000_000)) # 几乎不占内存
3. 合适的数据结构:
# 存储大量布尔值
import array
from array import array as typed_array
# list: 每元素 ~28 bytes
bools_list = [True] * 1_000_000
# array: 每元素 1 byte
bools_array = typed_array('b', [1] * 1_000_000)
# numpy: 更紧凑
import numpy as np
bools_np = np.ones(1_000_000, dtype=np.bool_) # 每元素 1 byte + 固定开销
内存分析工具
tracemalloc(标准库):
import tracemalloc
tracemalloc.start()
# 执行代码
data = [i ** 2 for i in range(100_000)]
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics("lineno")
for stat in top_stats[:5]:
print(stat)
# 输出每行代码的内存分配量
memory_profiler(第三方):
# pip install memory_profiler
from memory_profiler import profile
@profile
def my_func():
a = [i for i in range(1_000_000)]
del a
b = {i: i for i in range(1_000_000)}
return b
# 输出每行的内存增量
objgraph(对象引用图):
import objgraph
# 查看内存中最多的对象类型
objgraph.show_most_common_types(limit=10)
# 找到特定对象的引用链(排查泄漏)
objgraph.show_backrefs(obj, max_depth=3)
常见面试问题
Q1: Python 内存泄漏怎么排查?
答案:
- tracemalloc 对比两个时间点的快照,找到内存增长的位置
- objgraph 查找意外增长的对象类型和引用链
- gc.get_referrers() 查看谁在引用某个对象
- memory_profiler 逐行分析内存增量
Q2: del 语句会立即释放内存吗?
答案:
del 只是删除引用(引用计数 -1),不一定立即释放内存:
- 如果引用计数变为 0 → 立即释放
- 如果还有其他引用 → 不释放
- 释放的小内存块会被 pymalloc 缓存在 Pool 中,不一定归还给操作系统