面试题答案
一键面试Python垃圾回收机制工作原理
- 引用计数:
- Python中每个对象都有一个引用计数,记录了当前指向该对象的引用数量。当创建一个新对象时,引用计数初始化为1。例如:
a = [1, 2, 3] # 列表对象引用计数为1
- 每当有新的引用指向该对象时,引用计数加1。如:
b = a # 此时列表对象引用计数变为2
- 当一个引用离开其作用域或者被显式赋值为
None
时,引用计数减1。例如:
b = None # 列表对象引用计数变回1 a = None # 列表对象引用计数变为0,此时该对象的内存会被释放
- 标记 - 清除:
- 解决循环引用问题。循环引用指两个或多个对象相互引用,导致它们的引用计数永远不会为0。例如:
class A: pass class B: pass a = A() b = B() a.b = b b.a = a
- Python会定期启动标记 - 清除机制。它首先会暂停程序,标记所有活动对象(即可以从根对象(如全局变量、栈上的变量等)访问到的对象),然后清除未标记的对象(这些对象就是垃圾对象,由于循环引用导致引用计数不为0,但实际已无法从根对象访问到)。
- 分代回收:
- Python将对象分为不同的代(通常有三代)。新创建的对象放在第0代。
- 每次垃圾回收时,如果对象经过一次垃圾回收后仍然存活,就会被移到下一代。
- 不同代的垃圾回收频率不同,第0代回收频率最高,因为新创建的对象更有可能很快变成垃圾。随着代的增加,回收频率降低。这是基于一个经验假设:存活时间越久的对象,越有可能长期存活。
根据垃圾回收机制特点调整代码策略实现更优内存管理
- 减少不必要的引用:
- 避免在不必要的地方保持对对象的引用。例如,在函数内部,如果某个变量在函数执行完后不再需要,及时将其赋值为
None
,这样可以使该对象的引用计数减少,更快地被垃圾回收。
def process_data(): data = [1, 2, 3, 4, 5] # 创建数据列表 result = sum(data) data = None # 数据不再需要,释放引用 return result
- 避免在不必要的地方保持对对象的引用。例如,在函数内部,如果某个变量在函数执行完后不再需要,及时将其赋值为
- 处理循环引用:
- 手动打破循环引用:在适当的时候,手动将相互引用的对象的引用设置为
None
。例如:
class A: pass class B: pass a = A() b = B() a.b = b b.a = a # 处理完相关逻辑后 a.b = None b.a = None
- 使用弱引用:
weakref
模块提供了弱引用的功能。弱引用不会增加对象的引用计数,当对象的其他强引用都消失后,即使存在弱引用,对象也会被垃圾回收。例如:
这样,当import weakref class A: pass class B: pass a = A() b = B() a.b = weakref.ref(b) # 使用弱引用 b.a = weakref.ref(a)
a
和b
的其他强引用消失后,它们会被垃圾回收,不会因为循环引用导致内存泄漏。 - 手动打破循环引用:在适当的时候,手动将相互引用的对象的引用设置为