总结
| 描述 | 备注 | |
|---|---|---|
| 引用计数 | 对象被赋值给变量,引用计数+1;引用计数为0,会被系统垃圾回收 | |
| 标记清除 | 不可达(从一个节点遍历,不可达的对象进行释放) | |
| 分代收集 | 对象分为3代,本轮没有被回收的对象,放入下一代 | |
| objgraph | 排查内存泄漏 |
垃圾回收
引用计数
- 对象无法被删除,一般通过系统进行垃圾回收进行删除,垃圾回收的判断依据为引用计数
- 引用计数系统函数
sys.getrefcount(val),统计一个对象被引用的次数
手动释放内存
- 删除变量对对象的引用,
del a - 强制调用gc.collect(),清理没有引用的对象 'gc.collect()'
import gc
show_memory_info('initial')
a = [i for i in range(10000000)]
show_memory_info('after a created')
del a
gc.collect()
show_memory_info('finish')
print(a)
########## 输出 ##########
initial memory used: 48.1015625 MB
after a created memory used: 434.3828125 MB
finish memory used: 48.33203125 MB
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-153e15063d8a> in <module>
11
12 show_memory_info('finish')
---> 13 print(a)
NameError: name 'a' is not defined
标记清除(不可达)
对于一个有向图,如果从一个节点出发进行遍历,并标记其经过的所有节点;那么,在遍历结束后,所有没有被标记的节点,我们就称之为不可达节点。显而易见,这些节点的存在是没有任何意义的,自然的,我们就需要对它们进行垃圾回收。
分代收集
Python 将所有对象分为三代。刚刚创立的对象是第 0 代;经过一次垃圾回收后,依然存在的对象,便会依次从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。事实上,分代收集基于的思想是,新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活。因此,通过这种做法,可以节约不少计算量,从而提高 Python 的性能。
调试内存泄漏 objgraph
一个非常好用的可视化引用关系的包
mac按照步骤
-
pip install objgraphpython安装objgraph -
pip install xdotpython安装xdot -
brew install graphvizbrew安装graphviz,用于将dot文件转换为pngdot objgraph-plfv1m1h.dot -T png -o pic.png
实例
import objgraph
a = [1, 2, 3]
b = [4, 5, 6]
a.append(b)
b.append(a)
objgraph.show_backrefs([a])
如下图为引用关系,
- a指向list 4items,
- b指向list 4items;
-
list 4items存在循环引用
image.png













网友评论