python拾遗7 - 垃圾回收

2020-05-05  本文已影响0人  天命_风流

垃圾回收机制

相比 C++ 的手动回收内存,python 的垃圾回收机制可谓是省心省力,判断是否回收一块内存,主要有三点:

1 计数引用

也就是最为常见的回收方式,当对一块内存的引用计数为 0 时,证明没有方法再调用这块内存,执行回收。

另你可以使用 sys.getrefcount( a ) 来查看一个变量的引用情况

2 标记清除

上面的方式非常简单,但是 python 的回收机制没有这么简单,当产生循环引用的时候,第一种方法就无能为力了:

def func():
    show_memory_info('initial')
    a = [i for i in range(10000000)]
    b = [i for i in range(10000000)]
    show_memory_info('after a, b created')
    a.append(b)
    b.append(a)

func()
show_memory_info('finished')

########## 输出 ##########

initial memory used: 47.984375 MB
after a, b created memory used: 822.73828125 MB
finished memory used: 821.73046875 MB

这时,我们要使用标记清除算法,我们可以用图的概念理解它:对一个有向图,如果从一个指定的结点出发,遍历所有结点,并进行标记。遍历结束后,没有被标记的节点就是不可达节点。
显然,这种不可达的节点是没有意义的,我们可以回收它的内存。

3 分代收集

引用专栏中的话解释:

而分代收集算法,则是另一个优化手段。

Python 将所有对象分为三代。刚刚创立的对象是第 0 代;经过一次垃圾回收后,依然存在的对象,便会依次从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。

事实上,分代收集基于的思想是,新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活。因此,通过这种做法,可以节约不少计算量,从而提高 Python 的性能。

4 手动删除

调试内存引用

使用 objgraph 模块,可以生成一个可视化的引用关系图。

import objgraph

a = [1, 2, 3]
b = [4, 5, 6]

a.append(b)
b.append(a)

objgraph.show_refs([a])
引用关系
import objgraph

a = [1, 2, 3]
b = [4, 5, 6]

a.append(b)
b.append(a)

objgraph.show_backrefs([a])
这个函数展示的信息更加全面
上一篇下一篇

猜你喜欢

热点阅读