python内存泄漏

python 内存泄漏定位

不同的语言有不同定位的方式。对于golang 而言。pprof 工具已经足够了。C,C++,java 更是有自身的监控定位机制。这里单单阐述python的 内存泄漏。

观察

首先 我们可以从监控工具上看到内存的异常告警。于是开始定位是什么问题导致的。

  • 登录到具体容器上。
  • ps -auxf 查看具体是哪个进程导致的内存暴涨。(一般也就是单服务容器)

定位思路

业务侧定位

  • 最近新上线的代码 通过对比排查
  • 对大表的select 操作,比如需要下载一个很大的excel。中间对数据操作不停的生成新的集合,导致数据量巨大。
  • 全局变量不停增加数据。
  • 程序GC 不能回收对象,针对python 而言,循环引用对象,自己实现了__del__ 方法。
  • python GC 被禁止。

以上的一些方法都是依靠对代码有一定的熟悉程度。对新增的东西进行防范。

工具侧定位

对于进程而言,对正在执行中的进程我们可以使用gdb 的方式attach 到这个进程。而gdb主要也是查找调用堆栈。对内存的展示和统计并不具备特别的优势。

针对python 的两个工具。没有侵入性

pyrasite

Pyrasite is a library and a set of tools for injecting code into running Python programs.

安装

这里注意gdb 需要到8 以上。否则无法attach 到进程上。

pip install urwid 
apt-get install python-meliae
apt update; apt install -y gdb(必须升级到8以上)

使用

包含三个命令行

  • pyrasite
  • pyrasite-shell
  • pyrasite-memory-viewer

pyrasite -l 显示可以使用的脚本
很少使用

pyrasite-memory-viewer

使用命令pyrasite-memory-viewer pid查看当前进程的最大对象

pyrasite-memory-viewer 

改命令可以生成对象的详细信息
(address, size, refs)

生成文件到/tmp 目录下
默认是没有排序的,所以我们需要进行排序

以下脚本对生成的文件进行了排序。

import json

if __name__ == '__main__':
        path = "/tmp/pyrasite-47-objects.json"
        ans = []
        with open(path, 'r') as f:
                for l in f:
                        if l:
                                try:
                                        i = json.loads(l)
                                        # if i['type'] == 'dict':
                                        ans.append(i)
                                except Exception as e:
                                        print i
				        
        ans = sorted(ans, key=lambda x: -x['size'])
        with open("ans.json", 'w') as f:
                for i in ans:
                        f.write("%s \n" % (i))

pyrasite-shell

使用这种方式可以attach 进去一个进程。

pyrasite-shell 

常规检测

import gc
gc.isenabled()  # 判断gc是否正在工作
gc.get_dbug()  # 判断gc是否开启了debug 模式
gc.garbage  # 获取gc无法被释放的对象

import ctypes
obj = ctypes.cast(, ctypes.py_object).value  #通过地址或者id(刚刚json文件中)来获取当前对象,可以知道对应引用的关系链

objgraph

主要用来看对象的关联关系,配合pyrasite-shell 来使用

安装

apt-get install graphviz
pip install xdot

使用

import ctypes
obj = ctypes.cast(, ctypes.py_object).value  #通过地址或者id(刚刚json文件中)来获取当前对象,可以知道对应引用的关系链
import objgraph
objgraph.show_refs([obj], filename="test.png")

小结

  • pyrasite-memory-viewer 生成对象以及内存消耗
  • 脚本排序 定位前几个消耗比较大的对象
  • pyrasite-shell 通过内存地址解析
  • 生成图片分析调用关系

你可能感兴趣的:(python,工作工具,实战)