python内存泄漏解决

一、目录

1 定义

2 内存泄漏的常见原因

3 检测

4 解决方法

二、实现

  1. 定义

    程序在使用完内存后未正确释放,导致内存占用不断增加,最终耗尽内存资源。python中,由于提供自动内存管理机制(垃圾回收),内存泄漏问题比较少,但仍然会发生。

  2. 内存泄漏的常见原因

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代码中使用了动态分配的内存,但没有及时释放,就会导致内存泄漏。

  1. 检测

    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
  2. 解决方法

    1. 弱引用`

    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}") #

  3. 避免创建全局变量

  4. 采用多线程,线程结束则进行回收。

  5. 避免使用循环引用。

  6. 正确使用引用库。

相关推荐
im_AMBER10 分钟前
学习日志05 python
python·学习
大虫小呓15 分钟前
Python 处理 Excel 数据 pandas 和 openpyxl 哪家强?
python·pandas
哪 吒28 分钟前
2025B卷 - 华为OD机试七日集训第5期 - 按算法分类,由易到难,循序渐进,玩转OD(Python/JS/C/C++)
python·算法·华为od·华为od机试·2025b卷
-凌凌漆-30 分钟前
【Qt】QStringLiteral 介绍
开发语言·qt
程序员爱钓鱼31 分钟前
Go语言项目工程化 — 常见开发工具与 CI/CD 支持
开发语言·后端·golang·gin
军训猫猫头1 小时前
1.如何对多个控件进行高效的绑定 C#例子 WPF例子
开发语言·算法·c#·.net
真的想上岸啊1 小时前
学习C++、QT---18(C++ 记事本项目的stylesheet)
开发语言·c++·学习
明天好,会的1 小时前
跨平台ZeroMQ:在Rust中使用zmq库的完整指南
开发语言·后端·rust
摸爬滚打李上进2 小时前
重生学AI第十六集:线性层nn.Linear
人工智能·pytorch·python·神经网络·机器学习
丁劲犇2 小时前
用 Turbo Vision 2 为 Qt 6 控制台应用创建 TUI 字符 MainFrame
开发语言·c++·qt·tui·字符界面·curse