python 内存异常的几种情况
- 代码内出现循环引用
- 全局变量数据太多
- 进程加载大量数据,长久持有不释放
现象
线上生产环境一些 tornado 服务(主要提供rest服务)进程占用内存过大:百兆到1G ,测试环境的同样服务未出现异常。
观察分析
1.确定是否是个别进程的特有现象
在一套环境中部署不同的tornado的服务,排除了tornado和第三方库的可能性。
2.利用linux top 等命令观察异常服务进程内存的增长情况
人工观察有异常内存的服务进程(2~3个小时观测一次),发现其内存占有率并不完全统一,即在进程启用之后,有的进程内存占有过大,有的正常,但是在相当长一段时间之后(一天以后),所有进程内存占有几乎趋于一个稳定的比较大的值。由此可以推断出以下几种情况:
- 生产环境请求复杂,测试环境和生产环境表现不一致,有可能是对某些api的不合法的请求(非法参数未处理)导致内存占用过大
- 某些api(单次请求的数据量较大)的并发量太大,同一时间内存占有量过大
- 隐式的改变了全局变量的值,导致变量数据增大,比如全局的list或者dict数据不断被添加
- 其他未知情况
对代码进行静态分析和检查, 排除了全局变量和循环引用的问题。
侦测线上api调用前后对进程内存的影响
为了能够非常细致的观测到线上api调用前后的进程内存占用率,在api调用的入口记录了当前进程的内存占用,并对日志以进程的id来区分,由于tornado的单进程特性,也可以用端口号来区分,这样日志的划分更稳定,毕竟进程id是个变数。
1 |
|
psutil 提供了获取进程资源占用如内存,cpu,磁盘,网络等的api。为了能查看api调用的上下文环境,日志中还记录了api的请求参数。
解决
通过的日志分析发现,一个api在某些参数的边界未做处理时,会导致一部分很大的数据被加载到内存中。至此,这个问题的根源终于被找到了。
不过一个疑问是:python的进程内存增大之后,是否会让python解释器认为,该进程使用的峰值内存就是如此而不愿意交换给os呢