165 字
1 分钟
Python 内存管理与性能优化
一、内存管理机制
1.1 引用计数
import sys
# 每个对象维护一个引用计数a = [] # 引用计数 +1b = a # 引用计数 +1print(sys.getrefcount(a)) # 3 (包括 getrefcount 的临时引用)
del a # 引用计数 -1del b # 引用计数 -1 -> 对象被回收
# 引用计数为 0 时,对象立即被销毁1.2 循环引用问题
# 循环引用导致引用计数无法归零class Node: def __init__(self): self.next = None
a = Node()b = Node()a.next = b # a -> bb.next = a # b -> a
# 引用计数:a=1, b=1(相互引用)# 无法通过引用计数回收,造成内存泄漏
# 解决:标记-清除(Mark-Sweep)算法import gcgc.collect() # 手动触发垃圾回收1.3 分代回收
import gc
# Python 将对象分为三代# 第 0 代:新创建的对象# 第 1 代:经历一次 GC 仍存活的对象# 第 2 代:经历两次 GC 仍存活的对象
# 分代阈值print(gc.get_threshold()) # (700, 10, 10)# 触发条件:第 0 代对象数量 > 700
# 分代回收策略# 第 0 代:频繁回收# 第 1 代:次频繁回收# 第 2 代:很少回收
# 自动回收gc.enable() # 启用自动回收gc.disable() # 禁用自动回收二、内存泄漏与排查
2.1 常见内存泄漏
# 1. 全局变量引用leaked_data = []
def add_data(item): leaked_data.append(item) # 数据永不释放
# 2. 闭包引用def create_leak(): data = [1, 2, 3] def inner(): return data # data 被闭包持有 return inner
# 3. 循环引用class Node: def __init__(self): self.self_ref = self # 循环引用
# 4. 监听器未移除class EventEmitter: def __init__(self): self.listeners = []
def on(self, event, callback): self.listeners.append((event, callback))
# 如果没有 off() 移除,监听器会累积
# 5. 缓存未清理cache = {}
def get_data(key): if key not in cache: cache[key] = load_data(key) # 缓存无限增长 return cache[key]2.2 tracemalloc 排查
import tracemalloc
# 启动跟踪tracemalloc.start()
# ... 执行代码 ...
# 获取快照snapshot = tracemalloc.take_snapshot()
# 显示最大内存占用top_stats = snapshot.statistics('lineno')for stat in top_stats[:10]: print(stat)
# 按文件名过滤stats = snapshot.filter_traces(( tracemalloc.Filter(False, "<module>"),))2.3 objgraph 排查
# pip install objgraph
import objgraph
# 显示增长最多的对象类型print(objgraph.show_most_common_types(limit=10))
# 显示某个类型的所有实例print(objgraph.by_type('MyClass'))
# 统计某个对象的引用obj = some_object()print(objgraph.find_refchain(obj, max_depth=5))三、slots 优化
3.1 内存优化
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
# 对比内存占用obj1 = WithoutSlots(1, 2)obj2 = WithSlots(1, 2)
print(sys.getsizeof(obj1)) # 56 bytes (含 __dict__)print(sys.getsizeof(obj2)) # 40 bytes (更小)
# 注意:slots 不影响实例方法的内存3.2 防止动态属性
class SafeClass: __slots__ = ['x', 'y']
def __init__(self, x, y): self.x = x self.y = y
obj = SafeClass(1, 2)obj.z = 3 # AttributeError: 'SafeClass' object has no attribute 'z'四、性能优化技巧
4.1 避免全局变量查找
# 慢:每次访问 math 模块都需查找def slow_sin(): import math for i in range(1000): math.sin(i)
# 快:模块级导入import math
def fast_sin(): for i in range(1000): math.sin(i)4.2 列表操作优化
# 慢:append in loopresult = []for i in range(10000): result.append(i * 2)
# 快:列表推导式result = [i * 2 for i in range(10000)]
# 更快:生成器(内存)result = (i * 2 for i in range(10000))
# 字符串拼接优化# 慢s = ""for i in range(1000): s += str(i)
# 快parts = []for i in range(1000): parts.append(str(i))s = "".join(parts)
# 最快(如果可能)s = "".join(str(i) for i in range(1000))4.3 map/filter 替代循环
# map 比循环快import time
start = time.perf_counter()result = list(map(lambda x: x * 2, range(1000000)))print(f"map: {time.perf_counter() - start:.4f}s")
start = time.perf_counter()result = [x * 2 for x in range(1000000)]print(f"list comp: {time.perf_counter() - start:.4f}s")4.4 使用局部变量
# 慢:全局变量查找开销def slow_func(): for i in range(1000): value = math.sin(i) + math.cos(i) return value
# 快:缓存局部变量def fast_func(): sin = math.sin cos = math.cos for i in range(1000): value = sin(i) + cos(i) return value4.5 itertools 优化
from itertools import islice
# 迭代器替代列表切片# 慢data = list(range(1000000))subset = data[100:200]
# 快:使用 islicesubset = list(islice(range(1000000), 100, 200))五、缓存与记忆化
5.1 lru_cache
from functools import lru_cache
@lru_cache(maxsize=128)def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2)
# 缓存信息print(fibonacci.cache_info())# CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)
fibonacci(10)print(fibonacci.cache_info())# CacheInfo(hits=8, misses=11, maxsize=128, currsize=11)
# 清除缓存fibonacci.cache_clear()5.2 自定义缓存
from functools import lru_cacheimport time
# 带过期时间的缓存class Cache: def __init__(self, ttl=60): self.cache = {} self.ttl = ttl
def get(self, key): if key in self.cache: value, timestamp = self.cache[key] if time.time() - timestamp < self.ttl: return value del self.cache[key] return None
def set(self, key, value): self.cache[key] = (value, time.time())
def clear(self): self.cache.clear()六、常用标准库性能对比
| 操作 | 低效写法 | 高效写法 |
|---|---|---|
| 列表创建 | list(range(n)) | [i for i in range(n)] |
| 字符串拼接 | s += str(i) | ''.join([str(i)]) |
| 成员判断 | i in list | i in set |
| 唯一元素 | list(set(items)) | dict.fromkeys(items).keys() |
| 统计计数 | items.count(x) | collections.Counter(items) |
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时
相关文章 智能推荐
1
Go 面试题
面试 面试中常见的 Go 语言题目——map 并发安全性、context 机制、GC 原理、GMP 调度模型等知识点整理。
2
Python 面向对象与设计模式
面试 Python 面向对象编程——类变量与实例变量、继承与 MRO、常见设计模式、单例模式实现。
3
MySQL 面试题
面试 面试中常见的 MySQL 题目——索引原理、事务隔离级别、锁机制、日志系统、SQL 优化等知识点整理。
4
计算机基础面试题
面试 面试中常见的计算机基础题目——网络七层模型、进程与线程、内存管理、系统调用等核心知识点整理。
5
Redis 面试题
面试 面试中常见的 Redis 题目——数据结构、持久化、集群方案、缓存穿透/击穿/雪崩、分布式锁等知识点整理。






