绝大多数通常情况下,Python 程序员无需像 C 程序员那样手动管理内存,Python 解释器会自动进行垃圾回收。虽然不需要手动管理内存,但知道了 Python 内存中的垃圾回收的原理,可以避免写出内存溢出(OOM out of memory)的程序。
Python 解释器是怎么自动进行垃圾回收的呢? 两种方案:
- 当引用计数为 0 时,执行垃圾回收。
Python 的世界里,万物皆对象,我们所定义的变量,都是对象的一个引用,当有对象指向一个对象时,引用计数就增加 1,当一个变量的生命周期结束时,比如函数调用完毕时,引用计数就会减少,当引用计数为 0 时, Python 解释器自动进行对变量进行垃圾回收。
- 当出现互相引用时,执行垃圾回收。
Python 使用标记清除算法和分代收集算,来启用针对循环引用的自动垃圾回收,这一点我也不是很熟悉,极客上的老师是这么解释的:
先来看标记清除算法。我们先用图论来理解不可达的概念。对于一个有向图,如果从一个节点出发进行遍历,并标记其经过的所有节点,那么在遍历结束后,所有没有被标记的节点,我们就称之为不可达节点。显而易见,这些节点的存在是没有任何意义的,自然,我们就需要对它们进行垃圾回收。
当然,每次遍历全图,对于 Python 而言是一种巨大的浪费。所以在 Python 的垃圾回收实现中,标记清除算法使用双向链表维护一个数据结构,并且只考虑容器类的对象(只有容器类的对象才有可能出现循环引用),而分代收集算法,则是另外一个优化手段。
Python 将所有对象分为三代。刚刚创立的对象是第 0 代,经过一次垃圾回收后,依然存在的对象,便会从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。
事实上,分代收集基于的思想是,新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活,因此这种做不不仅节省计算量,更提高 Python 的性能。
能否手动管理内存
当然可以,执行以下语句就可以释放变量 a 占用的内存空间:
import gc
a=[1,2,3,45]
del a
gc.collect()
调用 del a 来删除一个对象,调用 gc.collect() 来手动启用垃圾回收。
(完)
网友评论