问题描述
A服务,是一个检测MGR集群主节点是否发生变化的服务,使用python语言实现的。 针对每一个集群,主线程会建立一个子线程,并由子线程去检测。子线程会频繁的建立和销毁。html
上线之后,因为常常会有功能发布,从而重启服务,开始一段时间没有发现问题。 半个月前的周二服务发布后,大约一周时间,没有再发布。到周末的时候,忽然告警系统负载高,通过排查,发现内存几乎耗尽,并查到是A服务占用巨大内存,没有释放。python
排查过程
已经肯定,A服务是存在内存泄露的,究竟是什么地方内存使用完,却没有释放呢? 这是一个使人头疼的问题,之前确实没有遇到过Python的内存泄露。函数
首先,网上搜索关于python内存泄漏的问题。大致了解到,Python的内存回收是基于引用计数的,也就是说,若是某个对象被使用一次,引用计数就会增长1。对象的引用计数为0时,内存就会被回收掉。工具
常见的致使内存泄露的状况有两种:oop
(1)对象一直被全局变量使用,全局变量生命周期比较长,因此内存一直得不到释放。
(2)循环引用中的对象定义了__del__的状况.
网上提供了各类用于排查内存泄露的工具,例如objgraph、guppy、pympler等,其具体使用参考文后的连接。优化
看了半天这些工具的使用,感受仍是应该看看本身代码,是否是存在对象使用完,可是一直被引用的状况。spa
首先,排查内存泄露的位置是在主线程仍是子线程。经过查看,发现「子线程一直在执行」与「子线程频繁建立和退出」两种状况下,内存消耗差异较大, 并且「子线程一直在执行」内存消耗很小。这样,就能够定位到,内存泄露位置是在主线程或「子线程loop以前的代码」。线程
接着,屏蔽子线程,发现内存正常。调试
因此,定位到问题是在「子线程loop以前的代码」中。 最后,发现是频繁调用第三方包的函数致使的。htm
解决办法
找到问题的缘由了,那么解决方法就好办了。改用其余的包或修改使用方式,绕开这个大坑。