• tracemalloc分析内存使用情况与泄露


    tracemalloc分析内存使用情况与泄露

    1.概述

    python内存管理是通过引用计数执行的,如果指向某个对象的引用全部过期,那么受引用的对象就可以从内存中清除,从而给其他数据腾出空间。理论上讲,python开发不用担心程序如何分配和释放内存,因为python系统本身以及Cpython运行环境会自动处理这些问题。
    但实际情况程序会因为没有及时释放不再需要引用的数据耗尽内存。下面通过一些方法来看下内存使用情况。

    2.查看gc引用对象总数

    下面是被测试代码,这个代码可以创建对象,在gc中产生引用对象。

    import os
    
    class MyObject:
        def __init__(self):
            self.data = os.urandom(100)
    
    def get_data():
        values = []
        for _ in range(100):
            obj = MyObject()
            values.append(obj)
        return values
    
    def run():
        deep_values = []
        for _ in range(100):
            deep_values.append(get_data())
        return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    下面的代码用来输出当前gc引用对象的数量

    import gc
    
    # 获取运行前gc引用对象数量
    found_objects = gc.get_objects()
    print('Before:', len(found_objects))
    
    # 导入待测试模块
    import waste_memory
    
    # 运行待测试代码的函数
    hold_reference = waste_memory.run()
    
    # 获取运行代码后gc引用对象数量
    found_objects = gc.get_objects()
    print('After: ', len(found_objects))
    for obj in found_objects[:5]:
        print(repr(obj)[:100])
    
    print('...')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行上面的代码,下面是gc引用的对象总数。

    Before: 28834
    After:  28923
    
    • 1
    • 2

    3.tracemalloc查看内存分配情况

    3.1.查看内存分配情况

    上面只输出了gc的总数,对于分析内存分配情况没有太多的指导意义,tracemalloc模块能够追溯到分配它的位置,因此我们可以在之前模块前后对内存使用情况做个快照,分析两个快照之间的区别。

    下面是被测试代码

    import tracemalloc
    
    tracemalloc.start(10)                      # Set stack depth
    time1 = tracemalloc.take_snapshot()        # Before snapshot
    
    import waste_memory
    
    x = waste_memory.run()                     # Usage to debug
    time2 = tracemalloc.take_snapshot()        # After snapshot
    
    stats = time2.compare_to(time1, 'lineno')  # Compare snapshots
    for stat in stats[:3]:
        print(stat)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    运行上面的代码,从结果中可以看出,每一条记录都有size与count指标,用来表示这行代码所分配的对象占用多少内存,以及对象的数量。通过对比就能发现占用内存较多的对象是由那几行代码分配的。

    /waste_memory.py:11: size=5120 B (+5120 B), count=80 (+80), average=64 B
    /waste_memory.py:14: size=4424 B (+4424 B), count=79 (+79), average=56 B
    /waste_memory.py:9: size=1704 B (+1704 B), count=8 (+8), average=213 B
    
    • 1
    • 2
    • 3

    3.2.查看栈信息

    tracemalloc还可以打印栈的追踪信息,下面把程序中分配内存最多的那行代码所对应的栈追踪信息打印出来,看看程序是沿着哪条路径触发这行代码的。

    
    import tracemalloc
    
    tracemalloc.start(10)
    time1 = tracemalloc.take_snapshot()
    
    import waste_memory
    
    x = waste_memory.run()
    time2 = tracemalloc.take_snapshot()
    
    stats = time2.compare_to(time1, 'traceback')
    top = stats[0]
    print('Biggest offender is:')
    # 打印栈信息
    print('\n'.join(top.traceback.format()))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    运行上面的代码

    Biggest offender is:
      File "/with_trace.py", line 14
        x = waste_memory.run()
      File "/waste_memory.py", line 23
        deep_values.append(get_data())
      File "/waste_memory.py", line 16
        obj = MyObject()
      File "/waste_memory.py", line 11
        self.data = os.urandom(100)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    visual studio code导入自定义模块(pycharm中能够运行的文件,vs code报错:未找到指定模块)
    【JAVA基础】专题课(综合案例上)
    2024MathorCup A题 赛后思路代码分享(分赛区一等奖)移动通信网络中 PCI 规划问题
    面向对象14:抽象类
    【面试专线】【基础知识】【JAVA】基础(二)
    AVR汇编(三):寻址方式
    深入理解JAVA垃圾收集器CMS,G1工作流程原理 GC流程图 什么社会触发Minor GC?触发MinorGC过程。Full GC 过程。
    EFK代替ELK方案7.17.3
    融合边界处理机制的学习型麻雀搜索算法
    面向对象编程之—抽象类和接口
  • 原文地址:https://blog.csdn.net/m0_38039437/article/details/128122965