python内存泄漏解决
一、目录
1 定义
(图片来源网络,侵删)
2 内存泄漏的常见原因
3 检测
4 解决方法
二、实现
-
定义
程序在使用完内存后未正确释放,导致内存占用不断增加,最终耗尽内存资源。python中,由于提供自动内存管理机制(垃圾回收),内存泄漏问题比较少,但仍然会发生。
-
内存泄漏的常见原因
a.循环引用:当两个或多个对象相互引用时,如果没有妥善地处理,可能会导致内存泄漏。垃圾回收器无法识别这种情况,因为这些对象不再被使用,但由于引用计数不为零,无法被垃圾回收。
class A(): def __init__(self): self.b = None class B(): def __init__(self): self.a = None a = A() b = B() a.b = b b.a = a 解决: # 打破循环引用 a.b = None b.a = None
# 错误示例:循环中创建大量临时对象 for i in range(1000000): temp_list = [i] * 1000000 # 大量临时对象 # 正确做法:不要在循环中创建大对象或者临时对象 # 或者在每次迭代后手动清理资源 del temp_list #清空对象 # 错误示例:对象间产生了强引用循环 class MyClass: def __init__(self): self.list_of_myself = [] def leak_memory(self): for i in range(1000000): self.list_of_myself.append(self) # 强引用循环 # 正确做法:使用弱引用或者在每次迭代后手动解除引用 # self.list_of_myself.pop() # 使用弱引用的示例 import weakref class MyClass: def __init__(self): self.list_of_myself = [] def leak_memory(self): for i in range(1000000): self.list_of_myself.append(weakref.ref(self)) # 使用弱引用 # 正确做法:定期清理弱引用后来的死对象 # 可以在适当的时候手动检查并清理弱引用 # 正确示例:使用生成器来避免大对象 def generate_data(n): for i in range(n): yield i # 使用生成器,不会创建大列表 for item in generate_data(1000000): # 处理数据 pass
b.全局变量:全局变量占用的内存会一直存在,直到程序结束。如果在程序中使用了大量的全局变量,或者没有及时释放不再使用的全局变量,可能会导致内存泄漏。
del 变量 gc.collect()
c.长期运行的进程:长期运行的进程可能会因为长时间的运行而导致内存泄漏。例如,在一个循环中创建大量的对象,但没有及时释放,就会导致内存泄漏。
采用多线程,线程结束则进行回收。
d.第三方库:使用第三方库时,如果没有正确地管理资源,可能会导致内存泄漏。例如,打开文件、数据库连接等资源没有正确关闭。
f = open('file.txt', 'w') f.write('hello')
e.C扩展模块:Python中的C扩展模块可能会导致内存泄漏。如果在C代码中使用了动态分配的内存,但没有及时释放,就会导致内存泄漏。
- 检测
from memory_profiler import profile @profile def load_data(): data = [] for i in range(10000): data.append(dict(id=i, name='name{}'.format(i))) return data if __name__ == '__main__': my_data = load_data() 代码行号 内存占用 内存增量 代码 Line # Mem usage Increment Occurrences Line Contents ============================================================= 4 62.7 MiB 62.7 MiB 1 @profile 5 def load_data(): 6 62.7 MiB 0.0 MiB 1 data = [] 7 66.0 MiB 0.5 MiB 10001 for i in range(10000): 8 66.0 MiB 2.8 MiB 10000 data.append(dict(id=i, name='name{}'.format(i))) 9 66.0 MiB 0.0 MiB 1 return data
- 解决方法
- 弱引用`
import weakref import numpy as np a = np.array([1, 2, 3]) b = weakref.ref(a) print(f"b:{b}") print(f"a:{a}") print("使用b()可以访问b引用的对象") print(f"b() = {b()}") #调用方法 a = None #杀死方法 print("====== 运行 a = None 后 ======") print(f"b:{b}") #
- 避免创建全局变量
- 采用多线程,线程结束则进行回收。
- 避免使用循环引用。
- 正确使用引用库。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。