本文目录导读:

- 使用生成器替代列表
- 使用slots限制实例属性
- 使用array模块存储数字
- 使用struct模块压缩数据结构
- 使用collections模块的命名元组
- 使用numpy进行数值计算
- 使用数组索引替代字典
- 及时删除不再使用的对象
- 使用lru_cache进行记忆化
- 实战案例:处理百万级数据
- 内存优化的最佳实践总结
在Python中节省内存占用有很多实用技巧,我来分享一些经过验证的案例和方法:
使用生成器替代列表
❌ 内存密集型
# 一次性加载所有数据到内存
def read_large_file(filename):
data = []
with open(filename, 'r') as f:
for line in f:
data.append(line.strip())
return data
# 占用内存:~800MB for 1GB file
✅ 内存友好型
# 使用生成器,按需读取
def read_large_file_efficient(filename):
with open(filename, 'r') as f:
for line in f:
yield line.strip()
# 占用内存:~1MB,无论文件多大
使用slots限制实例属性
❌ 传统类定义
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 每个实例都有__dict__,占用约56字节
✅ 使用slots
class Point:
__slots__ = ('x', 'y') # 限制只能有这两个属性
def __init__(self, x, y):
self.x = x
self.y = y
# 每个实例约占用40字节,节省约28%内存
实际测试对比:
import sys
class WithoutSlots:
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
# 创建100万个实例
points_without = [WithoutSlots(1, 2) for _ in range(1000000)]
points_with = [WithSlots(1, 2) for _ in range(1000000)]
print(f"Without slots: {sys.getsizeof(points_without[0])} bytes")
print(f"With slots: {sys.getsizeof(points_with[0])} bytes")
使用array模块存储数字
❌ 使用列表存储大量数字
numbers = [i for i in range(1000000)] # 占用:约28MB
✅ 使用array模块
from array import array
numbers = array('i', range(1000000)) # 'i' 表示整数
# 占用:约4MB(节省约85%内存)
使用struct模块压缩数据结构
import struct
# 原始方式:使用元组存储
users = [(12345, 67890, 100.5) for _ in range(100000)]
# 占用:约24MB
# 优化方式:使用struct
class User:
__slots__ = ('data',)
FORMAT = 'IIf' # 两个整数,一个浮点数
def __init__(self, id1, id2, value):
self.data = struct.pack(self.FORMAT, id1, id2, value)
def get_values(self):
return struct.unpack(self.FORMAT, self.data)
# 占用:约4MB(节省约83%内存)
使用collections模块的命名元组
from collections import namedtuple
import sys
# 普通类(使用__slots__)
class Student:
__slots__ = ('name', 'age', 'score')
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
# 使用命名元组
StudentTuple = namedtuple('StudentTuple', ['name', 'age', 'score'])
# 比较内存使用
s1 = Student('Alice', 20, 95)
s2 = StudentTuple('Bob', 22, 88)
print(f"Class with __slots__: {sys.getsizeof(s1)} bytes")
print(f"Named tuple: {sys.getsizeof(s2)} bytes")
使用numpy进行数值计算
import numpy as np # Python列表 py_list = [i for i in range(1000000)] # 占用:约28MB # NumPy数组 np_array = np.arange(1000000, dtype=np.int32) # 占用:约4MB(节省约85%内存)
使用数组索引替代字典
# ❌ 字典方式(内存密集)
transactions = {}
for i in range(1000000):
transactions[i] = {f'key_{j}': j for j in range(10)}
# 占用:大量内存
# ✅ 数组方式(内存友好)
import numpy as np
# 使用二维数组
transactions = np.zeros((1000000, 10), dtype=np.float64)
# 固定内存占用:80MB(1000000 * 10 * 8 bytes)
# 如果需要字典功能,使用索引映射
def get_transaction(transaction_id):
return transactions[transaction_id]
及时删除不再使用的对象
# 手动触发垃圾回收
import gc
def process_large_data():
large_data = load_large_dataset() # 加载大数据
result = process(large_data)
# 显式删除大对象
del large_data
# 触发垃圾回收(但不推荐频繁使用)
gc.collect()
return result
使用lru_cache进行记忆化
from functools import lru_cache
# 不使用缓存
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
# 使用缓存(避免重复计算和内存浪费)
@lru_cache(maxsize=128)
def fibonacci_cached(n):
if n < 2:
return n
return fibonacci_cached(n-1) + fibonacci_cached(n-2)
实战案例:处理百万级数据
import sys
from array import array
from collections import defaultdict
class MemoryEfficientProcessor:
def __init__(self):
# 使用array存储数据
self.values = array('d') # 双精度浮点数
def process_data(self, data_stream):
"""处理数据流"""
# 使用生成器处理
for item in data_stream:
# 使用__slots__风格的类
processed = self._process_item(item)
self.values.append(processed)
# 定期清理
if len(self.values) > 1000000:
self._flush_to_disk()
def _process_item(self, item):
# 处理单个项目
return item * 2
def _flush_to_disk(self):
# 将内存中的数据写入磁盘
with open('data_backup.bin', 'ab') as f:
self.values.tofile(f)
self.values = array('d')
# 使用示例
processor = MemoryEfficientProcessor()
data = (i for i in range(10000000)) # 使用生成器
processor.process_data(data)
内存优化的最佳实践总结
- 按需加载:使用生成器、迭代器替代列表
- 选择合适的数据结构:array替代list,slots替代dict
- 利用numpy:处理数值数据时使用numpy
- 避免不必要的复制:使用浅拷贝、引用传递
- 及时释放:删除不再使用的对象
- 使用C扩展:考虑使用Cython、numba等
- 监控内存使用:使用memory_profiler、tracemalloc等工具
通过这些技巧,通常可以将内存占用降低50%-90%,具体取决于你的应用场景,记得在优化时权衡内存使用和代码可维护性。