表 B 中;如果节点的 gc_ref 不为 0,那么这个对象就会被标记为“可达“(GC_REACHABLE
),对于”可达“对象,还要递归的将该节点可以到达的节点标记为”可达“;链表 B 中被标
记为”可达“的节点要重新放回到链表 A 中。在两次遍历之后,链表 B 中的节点就是需要
释放内存的节点。
分代回收:在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停
的时间,Python 通过分代回收(空间换时间)的方法提高垃圾回收效率。分代回收的基
本思想是:对象存在的时间越长,是垃圾的可能性就越小,应该尽量不对这样的对象进
行垃圾回收。CPython 将对象分为三种世代分别记为 0、1、2,每一个新生对象都在第 0
代中,如果该对象在一轮垃圾回收扫描中存活下来,那么它将被移到第 1 代中,存在于
第 1 代的对象将较少的被垃圾回收扫描到;如果在对第 1 代进行垃圾回收扫描时,这个
对象又存活下来,那么它将被移至第 2 代中,在那里它被垃圾回收扫描的次数将会更少
。分代回收扫描的门限值可以通过 gc 模块的 get_threshold 函数来获得,该函数返回一
个三元组,分别表示多少次内存分配操作后会执行 0 代垃圾回收,多少次 0 代垃圾回收
后会执行 1 代垃圾回收,多少次 1 代垃圾回收后会执行 2 代垃圾回收。需要说明的是,
如果执行一次 2 代垃圾回收,那么比它年轻的代都要执行垃圾回收。如果想修改这几个
门限值,可以通过 gc 模块的 set_threshold 函数来做到。
题目 008:说一下你对 Python 中迭代器和生成器的理解。
点评:很多人面试者都会写迭代器和生成器,但是却无法准确的解释什么是迭代器和生成器。如果你也有
同样的困惑,可以参考下面的回答。
迭代器是实现了迭代器协议的对象。跟其他编程语言不通,Python 中没有用于定义协议
或表示约定的关键字,像 interface、protocol 这些单词并不在 Python 语言的关键字列
表中。Python 语言通过魔法方法来表示约定,也就是我们所说的协议,而__next__和
__iter__这两个魔法方法就代表了迭代器协议。可以通过 for-in 循环从迭代器对象中取
出值,也可以使用 next 函数取出迭代器对象中的下一个值。生成器是迭代器的语法升级
版本,可以用更为简单的代码来实现一个迭代器。
扩展:面试中经常让写生成斐波那契数列的迭代器,大家可以参考下面的代码。
class Fib(object):
def __init__(self, num):
self.num = num
self.a, self.b = 0, 1
self.idx = 0
def __iter__(self):
return self
def __next__(self):
if self.idx < self.num:
self.a, self.b = self.b, self.a + self.b
self.idx += 1
return self.a
raise StopIteration()