关于 Python 内存泄漏

2018-10-10 22:23:30 +08:00
 Buffer2Disk
线上机器跑了一个 Python 的多线程的程序,运行了 2 天,发现貌似有内存泄漏的情况

htop 查了下真实内存使用达到 1G 左右(机器总共是 2G 内存)

但是 htop 上面查看 Python 程序本身只占了不到 10%的内存,整个机器上只有这一个 Python 程序

请问大家,这是 Python 程序的 内存泄漏 还是 句柄泄漏 了?

有没有什么好的办法来排查嘛? 我用了下检测工具查看 Python 程序自身是 dict 对象占用了最多的内存

4208 次点击
所在节点    Python
32 条回复
billlee
2018-10-10 23:05:20 +08:00
你就不能把 htop 调成按进程显示,然后按内存排序码?
MrGba2z
2018-10-10 23:16:16 +08:00
你这样启动试试再看看内存
MALLOC_ARENA_MAX=1 python app.py
Buffer2Disk
2018-10-10 23:29:44 +08:00
@billlee 内存排序过了,整个服务器就这一个程序在跑,它占的最多,9.9%
Buffer2Disk
2018-10-11 00:15:04 +08:00
@MrGba2z MALLOC_ARENA_MAX 不是个环境变量么,你确定这样能启动么。。。
MrGba2z
2018-10-11 00:32:27 +08:00
@Buffer2Disk 可以的你可以写个 dummy script 试试 起码 ubuntu 上可以
xiaoshenke
2018-10-11 00:36:44 +08:00
RES197 就是 197m 内存啊
Buffer2Disk
2018-10-11 00:46:06 +08:00
@MrGba2z 试了下你的这个参数,貌似好像有点效果,不过还是要上线 1-2 天观察看看
Buffer2Disk
2018-10-11 00:47:45 +08:00
@MrGba2z 网上推荐的值是 4, 看看这个 https://github.com/prestodb/presto/issues/8993
MrGba2z
2018-10-11 01:26:32 +08:00
@Buffer2Disk
简单说就是
如果 MALLOC_ARENA_MAX 设为 1 如果有明显下降 就说明这个是 glibc 的问题 或者说他(对多线程)的行为就是这样的 并不是你的程序 memory leak 了
但是这么做会有性能损失
别的解决办法还有 调整 M_TRIM_THRESHOLD 或者改用别的 allocator, 比如我们就换用了 tcmalloc
至于各种办法的优劣 你需要自己衡量下.
MrGba2z
2018-10-11 01:32:09 +08:00
你实际用的内存主要是看 RSS
如果你对性能要求很高 可以假装..无视如此庞大的 VSIZE(减少线程数也能降低)

MALLOC_ARENA_MAX 调小之后 会增大 memory congestion 的几率, tcmalloc 等能视觉上降低 VSIZE 也只是算法做了优化, 使用了更效率的 lock/unlock 机制.

默认 glibc 在线程初始化的时候会固定分配一块大约 100M 的内存, 但因为他没被使用 所以它只是 VSIZE
如果你有 20 个线程 每个实际用 1M 的内存
那么结果(使用 glibc 的默认设置)就是 20M 的 RSS 2G 的 VSIZE
aijam
2018-10-11 10:22:49 +08:00
> Python 程序本身只占了不到 10%的内存
看起来是至少有 8 个 python 进程,每个进程消耗 10%内存。
ChristopherWu
2018-10-11 10:26:36 +08:00
@aijam 对的。。top 上就占了 80%的内存了,说不定还没有截图完全其他 python 进程。
aijam
2018-10-11 10:55:05 +08:00
如果你没看到内存越用越多,你就不能说他是“泄漏”吧。一个进程 200mb (根据实际应用而定)完全可能是正常值。
Buffer2Disk
2018-10-11 17:01:40 +08:00
@aijam 我感觉不是你这么算的,照那么算的话,光 Python 进程已经占用 90%内存了,
但是你用 htop 或者 free -m 看 整个系统的实际使用物理内存是 50%
Buffer2Disk
2018-10-11 17:02:29 +08:00
@aijam 实际就是内存越用越多的,第一天 500M,第二天 900M,第三天 1200M
Buffer2Disk
2018-10-11 17:05:01 +08:00
@MrGba2z 设置了这个值好像没用,内存今天又开始慢慢增加了
查了一篇文章说在 redhat 6,glibc 2.12 版本上面设置这个值是无效的( glibc 的 bug )
--->https://yq.aliyun.com/articles/227924,

不知道是不是这个原因,如果是的话只有升级系统版本到 centos7 了
Buffer2Disk
2018-10-11 17:06:05 +08:00
上面的链接地址多了个 ,
https://yq.aliyun.com/articles/227924
aijam
2018-10-11 17:53:54 +08:00
@Buffer2Disk > 我感觉不是你这么算的,照那么算的话,光 Python 进程已经占用 90%内存了
一般就是把 RES 加起来的,估计父子进程可能共享了一部分 memory page (比如有 mmap 之类的调用)
Buffer2Disk
2018-10-11 18:04:02 +08:00
@aijam

Python 我不是很熟悉哈,感觉我开的 13 个线程,都是以进程的形式在系统存在的

那么每个进程使用的内存,在每个时段都一模一样,这也太巧了吧

而且除了主线程外,其他几个线程干的事情很简单,根本不会一个线程消耗到 197M 内存
aijam
2018-10-11 18:50:26 +08:00
@Buffer2Disk
> Python 我不是很熟悉哈,感觉我开的 13 个线程,都是以进程的形式在系统存在的
和熟不熟悉 Python 两回事,线程和进程的区别,虚拟内存等知识了解下。

> 那么每个进程使用的内存,在每个时段都一模一样,这也太巧了吧
道理上讲,子进程是复制父进程的内存空间的,但实际的内存使用是 copy on write 的。
我不确定 htop 的 RES 栏给出的是复制的内存空间,还是 copy on write 实际的内存使用,估计在不同系统下显示的结果都不一定相同,所以对这些数字的解释需要谨慎。
如果显示的是前者(复制的内存空间),就可以解释你看到的现象:RES 给出的是 fork 时复制的内存大小,而内存总使用量显示的是实际的使用大小。
下面这个链接印证了我的说法:
https://stackoverflow.com/questions/35596093/htop-shows-more-resident-memory-usage-than-what-the-machine-has

> 而且除了主线程外,其他几个线程干的事情很简单,根本不会一个线程消耗到 197M 内存
空说无凭,可能的话上代码吧。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/496498

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX