python gc

python 内存泄漏gc卡顿问题分析

Posted by zc on June 24, 2021

一、python 内存泄漏的2个可能原因

  • 循环引用,且循环引用的对象重写了__del__ 方法,导致python gc 发现后,无法回收导致内存增长,这种垃圾我们称为uncollectable 对象(可以回收的循环引用对象称为 unreachable);
  • 缓存或者全局容器,出现了大量正常对象,导致内存持续增长;

二、python 内存 回收机制简述

  • 内存回收,主要是以引用计数为主,每个对象维护了一个引用计数,当引用计数为0 时,对象内存空间会被立马释放掉。将内存回收时间摊平到每个对象回收上,使程序运行更加稳定,减少了像java 一样的stw现象;(正是因为这个引用计数的维护,一定程度上降低了python的性能,也是GIL 长期存在的部分原因)
  • 引用计数无法处理循环引用的对象,因此python 内存回收会配合GC来解决循环引用的问题。gc 以分代,标记清除为手段,识别出循环引用对象;python 新分配的对象,最终会落到3个双向链表中,称为 0代、1代、2代;
  • 什么时候会触发gc? 新增对象会放在0代里,当新增对象-释放的对象(引用计数为0被释放)达到一个阈值(threshold0),会触发0代的回收,按照一定的策略,识别出循环引用对象,并回收。当0代回收次数达到一个阈值(threshold1),会触发1代回收,当1代回收次数达到一个阈值(threshold2),会触发2代回收;阈值是可以通过gc.set_threshold(threshold0[, threshold1[, threshold2]])¶ ;
  • python 会有stw 现象吗?正常情况下,引用计数就可以保证内存不会增长,也就不会触发gc, 所以也就没有stw 现象。但是一旦出现循环引用或者内存泄漏,就会触发gc,特别是2代gc, 会导致stw 现象;