趣谈Python垃圾回收机制
今天唠点啥
上次发文看到有位朋友评论“来了,来了,他来了”,哈哈哈哈觉得挺逗。确实,老Amy今天又来啦[此处应该有掌声]~
我就寻思着,上篇文章车都开稳了,今天要怎么假装“正经”的跟大家唠点。来吧朋友,让我们一起举杯聊一聊垃圾是怎么回收的[饿,此辣鸡非彼辣鸡]…别走,听我叭叭。
啥是垃圾?
在Python程序运行的时候,会在内存中开辟一块空间,用于存放临时变量;当计算完成之后,就会将结果输出到永久性存储器中。如果数据量特别大,那内存空间管理不妥当的话就非常容易BOOM[爆内存],程序可能直接终止。
就比如说,老Amy住在40㎡的房间,非常喜欢购物[女银好可怕],买完就往家里一丢,从不清理。直到有一天,房子“爆炸了”。原因:惊!某女疯狂购物导致房间内存不够爆炸?
老Amy就跟老居老J哭诉这件事件,他们分别给我提供了相应的解决方案。
方案一
老居老J:“控几寄几,少购物”
我:“不购物,岂不是相当于不在Python写变量了?不可能!”
方案二
老居老J:“换大房子”
我:“选择将房子换成更大的确实能提高存储,但是贵阿[哭了]”
方案三
老居老J:“列出不用物品清单,放到小区回收箱”
我:“这可以,终于说了句’人话’了[嘿嘿]…”
所以,Python也是同理。但是,Python要怎么确认这个物品(对象)永远不会被调用了呢?
计数引用
在Python中,一切皆对象。所以,每一个变量,实际上都是对象的一个指针。所以,当这个对象的引用计数(指针数)为0的时候,说明它也变成了垃圾,需要被放到回收箱中。
def show_info(start):pid = os.getpid()p = psutil.Process(pid)info = p.memory_full_info()memory = info.uss/1024./1024print(f"{start}一共占用{memory:.2f}MB")def func():show_info("initial")li = [i for i in range(1000000)]show_info("created")func()
show_info("finished")Out[1]: initial一共占用26.40MB
Out[2]: created一共占用65.39MB
Out[3]: finished一共占用26.91MB
通过以上代码,就可以发现,调用函数func(),列表li被创建之后,内存由26.40MB增到了65.39MB。但是当函数内部代码执行完毕,返回到函数调用处时,内存又降为了26.91MB。[内心OS,简直是一场过山车呀]
这是因为,函数内部声明的列表li是局部变量,在函数返回后,局部变量的引用就会被注销掉;这个时候,列表li所指代对象的引用数为0,Python就会对其进行垃圾回收,因此之前占用的大量内存又回来了。
那有的朋友可能就会疑问:“那如果列表li是全局变量呢?”
OK,那我们一起来康康
def show_info(start):pid = os.getpid()p = psutil.Process(pid)info = p.memory_full_info()memory = info.uss/1024./1024print(f"{start}一共占用{memory:.2f}MB")def func():show_info("initial")global lili = [i for i in range(1000000)]show_info("created")func()
show_info("finished")Out[1]: initial一共占用26.36MB
Out[2]: created一共占用65.27MB
Out[3]: finished一共占用65.22MB
当通过global关键字将列表li声明为全局变量的时候,即使函数体内代码执行完毕,返回到函数调用处时,对列表li的引用仍然是存在的,所以对象不会被垃圾回收,依然占有大量内存。
同理,在列表li为局部变量时,我们也可以通过将它返回出去,并且在函数调用处用变量接收,这样也实现了对列表li的引用。垃圾回收也不会被触发。
def show_info(start):pid = os.getpid()p = psutil.Process(pid)info = p.memory_full_info()memory = info.uss/1024./1024print(f"{start}一共占用{memory:.2f}MB")def func():show_info("initial")li = [i for i in range(1000000)]show_info("created")return lires = func()
show_info("finished")Out[1]: initial一共占用26.27MB
Out[2]: created一共占用65.37MB
Out[3]: finished一共占用65.23MB
并且,我们可以通过sys.getrefcount()这个函数,来扒一扒Python内部的引用计数机制。
import sysa = [1,2,3]# 引用次数:2 一次:a 一次:getrefcount
print(sys.getrefcount(a)) def func(a):# 引用次数:4 一次:a 一次:函数调用 一次:函数参数 一次:getrefcountprint(sys.getrefcount(a)) func(a)# 引用次数:2 一次:a 一次:getrefcount 注:此时func调用已经释放
print(sys.getrefcount(a)) Out[1]: 2
Out[2]: 4
Out[3]: 2
注意
• getrefcount本身也会引入一次计数
• 函数调用时引入一次计数,以及函数参数引入一次计数
除此之外,来思考以下代码执行结果
import sys
a = [1,2,3]
print(sys.getrefcount(a)) # 2b = a
print(sys.getrefcount(a)) # 3c = b
d = c
print(sys.getrefcount(a)) Out[1]: 2
Out[2]: 3
Out[3]: 5
需要注意的是,a、b、c、d四个变量全部指向一个对象,getrefcount统计的是引用次数,所以结合getrefcount本身也会引入一次计数,一共是5次引用。
所以大家会发现,Python比老Amy智能多了,它会自动的去检测该对象是否是垃圾[对象是垃圾?..等着受罚把hh],以及将其回收。这也被称为是Python当中的垃圾回收机制。
当然,有的朋友也会问,就很饥渴的想要手动的释放内存[我看不太懂的亚子!],要怎么来做呢?
手动启动垃圾回收
其实百变不离其中,如果我们可以手动删除完对象的引用,然后强制调用gc.collect()清除没有引用的对象,其实也就是手动的启动对象的回收。
import sys
import gca = [1,2,3]print(sys.getrefcount(a))del a
gc.collect()
print(a)---------------------------------------------------------------------------
Traceback (most recent call last):File "D:/Amy/Basic/garbageCollection/demo.py", line 155, in <module>print(a)
NameError: name 'a' is not defined
到这儿,大家已经大概的掌握了Python垃圾回收机制中的引用计数法。能看到这里的朋友都非常的奈斯,如果对你有帮助的话,emmm…记得三连奥[不允许下次一定,hhh]
如果想要康康更多关于Python的文章,可以关注额滴公众号~支持支持程序媛,康桑思密达
趣谈Python垃圾回收机制相关推荐
- python 释放变量所指向的内存_通俗易懂的Python垃圾回收机制及内存管理
Python垃圾回收机制及内存管理 内存管理: 先定义一个变量 name='wxl' 那么python会在内存中开辟一小块区域存放"wxl",此时变量的值是我们真正想要存储的,wx ...
- python是不是特别垃圾-谈谈python垃圾回收机制
什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...
- python垃圾回收离职_谈谈python垃圾回收机制
什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...
- python垃圾回收机制原理_如何理解和掌握Python垃圾回收机制?
在编程世界里,当一个对象失去引用或者离开作用域后,它就会被当做垃圾而被自动清除,这就是垃圾回收机制.在现在的高级语言如Python.Java都使用了垃圾回收机制,不过与Java采用的垃圾收集机制不同, ...
- python 垃圾回收机制
DAY 18. python垃圾回收机制 python GC主要有三种方式 引用计数 标记清除 分代回收 其中,以引用计数为主. 18.1 引用计数(Reference Counting) <寻 ...
- python多线程详解 Python 垃圾回收机制
文章目录 python多线程详解 一.线程介绍 什么是线程 为什么要使用多线程 总结起来,使用多线程编程具有如下几个优点: 二.线程实现 自定义线程 守护线程 主线程等待子线程结束 多线程共享全局变量 ...
- python垃圾回收机制
python垃圾回收机制 现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄 ...
- 人生苦短,能让你更早下班的Python垃圾回收机制
人生苦短,只谈风月,谈什么垃圾回收. 据说上图是某语言的垃圾回收机制... 我们写过C语言.C++的朋友都知道,我们的C语言是没有垃圾回收这种说法的.手动分配.释放内存都需要我们的程序员自己完成.不管 ...
- 能让你更早下班的Python垃圾回收机制
人生苦短,只谈风月,谈什么垃圾回收. 据说上图是某语言的垃圾回收机制... 我们写过C语言.C++的朋友都知道,我们的C语言是没有垃圾回收这种说法的.手动分配.释放内存都需要我们的程序员自己完成.不管 ...
最新文章
- socket编码问题
- IndiaHacks 2016 - Online Edition (Div. 1 + Div. 2) A. Bear and Three Balls 水题
- pyspark 通过list 构建rdd
- Android开发面试题之Android四大组件
- java 密码生成器_Java课程设计-随机密码生成器
- 952开头的电话一天响两三次,不是诈骗就是推销,请问该怎么屏蔽呢?
- SQL实战之查找最晚入职员工的所有信息
- lp地址为什么位_为什么内存空间分配总是以64K为边界?
- Security+ 学习笔记54 安全政策
- unity animator 动画 结束后保持位移_Unity动画系统详解9:Target Matching是什么?
- 使用Scala编程计算级数
- Python小练习——电影数据集TMDB预处理
- DDR3之带宽、位宽和频率使用(MIGIP核里面的时钟结构)
- 广义线性模型之指数分布族期望和方差的推导
- 一根辣条铸就的百亿生意,卫龙是如何成龙的
- 如何解决“数据错误,循环冗余检查”
- 梅特勒-托利多 TCS-35 电子台秤
- TLD文件自定义标签
- 人工智能正在重塑人力资源的7种方式
- killall杀死nginx顽固进程
热门文章
- C# 使用 StreamReader 读取数据
- 大工21秋《钢筋混凝土结构课程设计》模大作业离线作业
- 徐州医科大学计算机专业在哪个校区,定了!徐州医科大学新校区选址东湖新城 !...
- 全球及中国工程起重机行业格局与十四五运营趋势研究报告2022版
- termux目录_Termux系列教程:新手必做的初始化配置!
- Word替换指定开头和结尾的文字(如字幕文件)
- 创建map集合的实现类添加员工和工资数据: 输出每个员工的信息和工资
- Java获取yyyymmddhhmmss格式时间
- 你真的了解Systrace吗?
- 怎样建设现代化养猪场?