面试题-python 垃圾回收机制?

前言

简历上写着熟悉 python 面试官上来就问:说下python 垃圾回收机制?一盆冷水泼过来,瞬间感觉 python 不香了。
Python中,主要通过引用计数(Reference Counting)进行垃圾回收。

引用计数

在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数器(ob_refcnt)。
程序在运行的过程中会实时的更新 ob_refcnt 的值,来反映引用当前对象的名称数量。

当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。
但是回收不是”立即”的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收。

sys.getrefcount() 可以查看对象的引用次数,先自己先有个class 创建一个对象,此时引用次数是1,由于 sys.getrefcount() 也会引用一次,所以看到的会在引用次数基础上+1

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
import sys

class MyObject():
def __init__(self):
self.x = 1

a = MyObject() # 创建一个对象
print("MyObject 引用次数:", sys.getrefcount(a)) # 查看引用次数

运行结果:MyObject 引用次数:2

导致引用计数 +1 的情况

  • 对象被创建,例如 a=23

  • 对象被引用,例如 b=a

  • 对象被作为参数,传入到一个函数中,例如func(a)

  • 对象作为一个元素,存储在容器中,例如list1=[a,a]

导致引用计数-1 的情况

  • 对象的别名被显式销毁,例如del a

  • 对象的别名被赋予新的对象,例如a=24

  • 一个对象离开它的作用域,例如 f 函数执行完毕时,func函数中的局部变量(全局变量不会)

  • 对象所在的容器被销毁,或从容器中删除对象

对象销毁

下面代码a增加一次引用,赋值给a后,b和a都是指向同一个对象,当我们不用的时候就可以用del 销毁对象a和b

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

import sys

class MyObject():
def __init__(self):
self.x = 1

a = MyObject() # 创建一个对象
print("MyObject 引用次数:", sys.getrefcount(a)) # 查看引用次数

# a增加一次引用
b = a
print("MyObject 引用次数:", sys.getrefcount(a)) # 查看引用次数

# 销毁对象b
del b
print("MyObject 引用次数:", sys.getrefcount(a)) # 查看引用次数

# 销毁对象a
del a

对象作为参数,传到函数里面也会被引用一次,看下面这个案例

import sys

a = [1, 2, 3]
print(sys.getrefcount(a)) # 2次
b = a
print(sys.getrefcount(a)) # 3次
c = b
d = b
e = c
f = e
g = d
print(sys.getrefcount(a)) # 8次

输出结果

2
3
8

a、b、c、d、e、f、g 这些变量全部指代的是同一个对象,而 sys.getrefcount() 函数并不是统计一个指针,而是要统计一个对象被引用的次数,所以最后一共会有 8 次引用。
如果我们一个个去销毁对象,很显然会浪费时间,于是可以用gc来垃圾回收了,gc.collect() 即可手动启动垃圾回收

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
import sys
import gc

a = [1, 2, 3]
print(sys.getrefcount(a)) # 2次
b = a
print(sys.getrefcount(a)) # 3次
c = b
d = b
e = c
f = e
g = d
print(sys.getrefcount(a)) # 8次

del a
gc.collect() # 垃圾回收

循环引用

当a对象引用b,b对象也引用a,两个互相引用的时候,互相引用导致它们的引用数都不为 0。
初始化的时候,会生成一个大的列表[i for i in range(100000)],导致占用很大的内存

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
import sys

class MyObject():
def __init__(self):
self.y = [i for i in range(1000000)]
self.x = 1

while True:
a = MyObject() # 创建一个对象
b = MyObject()
print("MyObject 引用次数a:", sys.getrefcount(a)) # 查看引用次数
print("MyObject 引用次数b:", sys.getrefcount(b)) # 查看引用次数
a.x = b # a的x属性赋值b
b.x = a # b的x属性赋值a
# 销毁对象a和b
del a
del b

运行一段时间后,可以观察内存的变化,会一直增加不释放

使用 gc.collect() 垃圾回收

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
import sys
import gc

class MyObject():
def __init__(self):
self.y = [i for i in range(1000000)]
self.x = 1

while True:
a = MyObject() # 创建一个对象
b = MyObject()
print("MyObject 引用次数a:", sys.getrefcount(a)) # 查看引用次数
print("MyObject 引用次数b:", sys.getrefcount(b)) # 查看引用次数
a.x = b # a的x属性赋值b
b.x = a # b的x属性赋值a
# 销毁对象a和b
del a
del b
gc.collect()

再次运行,内存就得到释放了

在Python中,主要通过引用计数进行垃圾回收;通过 “标记-清除” 解决容器对象可能产生的循环引用问题;通过 “分代回收” 以空间换时间的方法提高垃圾回收效率。

参考资料http://c.biancheng.net/view/5540.html
参考资料https://www.cnblogs.com/donghe123/p/13275183.html
参考资料https://testerhome.com/topics/16556

2021年第六期《python接口自动化+测试开发》课程,1月9号开学(火热报名中!)

本期上课时间:1月9号-4月18号,每周六、周日晚上20:30-22:30

(0)

相关推荐

  • Traceback具体使用方法

    Traceback具体使用方法详解,首先在之前做Java的时候,异常对象默认就包含stacktrace相关的信息,通过异常对象的相关方法printStackTrace()和getStackTrace( ...

  • ​解密 Python 中的对象模型

    作者:古明地盆 来源:https://www.cnblogs.com/traditional/p/13391098.html Python中一切皆对象 关于 Python,你肯定听过这么一句话:'Py ...

  • 第 111 天:Python 垃圾回收机制

    众所周知,Python 是一门面向对象语言,在 Python 的世界一切皆对象.所以一切变量的本质都是对象的一个指针而已. Python 运行过程中会不停的创建各种变量,而这些变量是需要存储在内存中的 ...

  • 说说Python中的垃圾回收机制?

    公众号新增加了一个栏目,就是每天给大家解答一道Python常见的面试题,反正每天不贪多,一天一题,正好合适,只希望这个面试栏目,给那些正在准备面试的同学,提供一点点帮助! 小猿会从最基础的面试题开始, ...

  • PHP垃圾回收机制的一些浅薄理解

    PHP垃圾回收机制的一些浅薄理解 相信只要入门学习过一点开发的同学都知道,不管任何编程语言,一个变量都会保存在内存中.其实,我们这些开发者就是在来回不停地操纵内存,相应地,我们如果一直增加新的变量,内 ...

  • [PHP小课堂]PHP垃圾回收机制的一些浅薄理解

    [PHP小课堂]PHP垃圾回收机制的一些浅薄理解 关注公众号:[硬核项目经理]获取最新文章 添加微信/QQ好友:[xiaoyuezigonggong/149844827]免费得PHP.项目管理学习资料 ...

  • 火山中文编程:012如何删除变量及垃圾回收机制介绍

    第一种方法,鼠标选中需要删除的变量,当鼠标选中后,选中的变量会高亮显示,这时候直接按键盘DELETE键即可快速删除变量,这种方法只有选中变量表格后才能使用,否则无效. 第二种方法删除变量的方法,鼠标放 ...

  • 关于JS垃圾回收机制

    一.垃圾回收机制的必要性 由于字符串.对象和数组没有固定大小,所以当它们的大小已知时,才能对它们进行动态的存储分配.JavaScript程序每次创建字符串.数组或对象时,解释器都必须分配内存来存储那个 ...

  • 浅谈浏览器垃圾回收机制

    javaScriipt 使用垃圾回收机制来自动管理内存 js 的回收机制目前分为两种方式:1.标记清除(各大浏览器主流算法)2.引用技术 一: 标记清除 这种算法的思想是给当前不使用的值加上标记,然后 ...

  • 垃圾回收算法有几种类型? 他们对应的优缺点又是什么?

    常见的垃圾回收算法有: 标记-清除算法.复制算法.标记-整理算法.分代收集算法 标记-清除算法 标记-清除算法包括两个阶段:"标记"和"清除". 标记阶段:确定 ...

  • Go 语言如何实现垃圾回收中的 Stop the World (STW)

    Illustration created for "A Journey With Go", made from the original Go Gopher, created by ...