python判断内存泄漏_python内存泄露memory leak排查记录

本文介绍了如何定位和解决Python内存泄露问题。在一个名为A的服务中,由于子线程频繁建立和销毁,导致内存耗尽。经过排查,发现在子线程启动前的代码存在内存泄露,特别是对第三方包函数的频繁调用。最终,通过更换包或调整使用方式成功解决了内存泄露问题。

问题描述

A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的。 针对每一个集群,主线程会建立一个子线程,并由子线程去检测。子线程会频繁的建立和销毁。html

上线之后,因为常常会有功能发布,从而重启服务,开始一段时间没有发现问题。 半个月前的周二服务发布后,大约一周时间,没有再发布。到周末的时候,忽然告警系统负载高,通过排查,发现内存几乎耗尽,并查到是A服务占用巨大内存,没有释放。python

排查过程

已经肯定,A服务是存在内存泄露的,究竟是什么地方内存使用完,却没有释放呢? 这是一个使人头疼的问题,之前确实没有遇到过Python的内存泄露。函数

首先,网上搜索关于python内存泄漏的问题。大致了解到,Python的内存回收是基于引用计数的,也就是说,若是某个对象被使用一次,引用计数就会增长1。对象的引用计数为0时,内存就会被回收掉。工具

常见的致使内存泄露的状况有两种:oop

(1)对象一直被全局变量使用,全局变量生命周期比较长,因此内存一直得不到释放。

(2)循环引用中的对象定义了__del__的状况.

网上提供了各类用于排查内存泄露的工具,例如objgraph、guppy、pympler等,其具体使用参考文后的连接。优化

看了半天这些工具的使用,感受仍是应该看看本身代码,是否是存在对象使用完,可是一直被引用的状况。spa

首先,排查内存泄露的位置是在主线程仍是子线程。经过查看,发现「子线程一直在执行」与「子线程频繁建立和退出」两种状况下,内存消耗差异较大, 并且「子线程一直在执行」内存消耗很小。这样,就能够定位到,内存泄露位置是在主线程或「子线程loop以前的代码」。线程

接着,屏蔽子线程,发现内存正常。调试

因此,定位到问题是在「子线程loop以前的代码」中。 最后,发现是频繁调用第三方包的函数致使的。htm

解决办法

找到问题的缘由了,那么解决方法就好办了。改用其余的包或修改使用方式,绕开这个大坑。

参考

内存泄漏排查工具在不同编程语言和环境中有所区别,以下是几种常见语言的内存泄漏排查工具及其使用方法。 ### Java 中的内存泄漏排查工具 1. **jstat**:这是 JDK 自带的一个命令行工具,用于监控 JVM 的垃圾回收情况。通过观察 GC 的频率和堆内存的变化,可以初步判断是否存在内存泄漏问题[^1]。 - 使用示例: ```bash jstat -gc <pid> 1000 ``` 2. **jmap**:同样属于 JDK 工具集的一部分,可用于生成堆转储快照(heap dump),并分析对象占用内存的情况。如果发现某些对象持续增长且未被释放,可能是内存泄漏的迹象。 - 使用示例: ```bash jmap -dump:live,format=b,file=heapdump.hprof <pid> ``` 3. **VisualVM / JVisualVM**:这是一个图形化工具,支持实时监控 JVM 内存、线程状态,并能对堆转储进行深入分析。它还可以与 MAT(Memory Analyzer Tool)配合使用,帮助识别“保留集”(retained set)和潜在的内存泄漏源[^1]。 4. **MAT (Memory Analyzer)**:专门用于分析由 jmap 生成的 heap dump 文件。它可以展示对象之间的引用关系,并提供“支配树”(Dominator Tree)视图来快速定位占用内存最多的对象[^1]。 5. **YourKit 和 JProfiler**:这两个是商业级性能分析工具,提供更高级的功能如 CPU/内存剖析、远程调试等。它们能够自动检测常见的内存泄漏模式,并给出优化建议[^1]。 ### Python 中的内存泄漏排查工具 1. **gc 模块**:Python 标准库中的 `gc` 模块提供了垃圾回收相关的接口。可以通过 `gc.get_objects()` 获取所有被追踪的对象列表,进而查找可能未被释放的对象[^4]。 2. **tracemalloc**:从 Python 3.4 开始引入的标准库,用于跟踪内存分配。它可以帮助开发者了解程序运行过程中哪些部分分配了最多的内存,并支持按文件或函数进行排序[^4]。 - 使用示例: ```python import tracemalloc tracemalloc.start() # Your code here snapshot = tracemalloc.take_snapshot() top_stats = snapshot.statistics('lineno') for stat in top_stats: print(stat) ``` 3. **mem_top**:基于 `gc` 模块封装的轻量级工具,能够快速显示占用内存最多的 N 个对象,适用于需要快速诊断场景[^4]。 4. **guppy**:一个强大的第三方库,允许对堆中的对象进行详细统计。虽然计算速度较慢,但其提供的信息非常全面,适合复杂应用的深度分析[^4]。 5. **objgraph**:通过绘制对象引用图的方式,直观展示对象之间的依赖关系。对于结构简单、对象种类较少的应用特别有用[^4]。 6. **Pympler**:另一个实用的第三方库,可以统计不同类型对象的内存使用情况,并获取单个对象的实际大小[^4]。 7. **pyrasite**:一种侵入式调试工具,可以直接连接到正在运行的 Python 进程中,动态修改数据和代码,非常适合处理难以复现的问题[^4]。 ### C/C++ 中的内存泄漏排查工具 1. **Valgrind**:专为 Linux 系统设计的内存调试工具,能够检测内存泄漏、越界访问等问题。其核心组件 `memcheck` 是最常用的模块之一。 - 使用示例: ```bash valgrind --leak-check=yes ./your_program ``` 2. **AddressSanitizer (ASan)**:集成于 GCC 和 Clang 编译器中的高效内存错误检测器,能够在运行时捕获多种类型的内存问题,包括泄漏、溢出等。 - 使用示例: ```bash gcc -fsanitize=address -g your_code.c -o your_program ./your_program ``` 3. **LeakSanitizer (LSan)**:作为 ASan 的一部分,专注于内存泄漏检测。相比 Valgrind,它的性能开销更低,更适合生产环境下的测试[^5]。 4. **Dr. Memory**:跨平台的内存分析工具,支持 Windows 和 Linux 平台。除了基本的泄漏检测外,还具备其他高级功能如堆栈跟踪、系统调用检查等[^6]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值