今天唠点啥

上次发文看到有位朋友评论“来了,来了,他来了”,哈哈哈哈觉得挺逗。确实,老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垃圾回收机制相关推荐

  1. python 释放变量所指向的内存_通俗易懂的Python垃圾回收机制及内存管理

    Python垃圾回收机制及内存管理 内存管理: 先定义一个变量 name='wxl' 那么python会在内存中开辟一小块区域存放"wxl",此时变量的值是我们真正想要存储的,wx ...

  2. python是不是特别垃圾-谈谈python垃圾回收机制

    什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...

  3. python垃圾回收离职_谈谈python垃圾回收机制

    什么是垃圾回收机制? 首先,咱先来解释名词,垃圾回收是不是就是将没用的,废弃的东西回收起来. 在坐的各位都没有女朋友对吧,那难以想象你们的房间会是一个什么样子,可能会有很多垃圾,很凌乱,自己也不收拾. ...

  4. python垃圾回收机制原理_如何理解和掌握Python垃圾回收机制?

    在编程世界里,当一个对象失去引用或者离开作用域后,它就会被当做垃圾而被自动清除,这就是垃圾回收机制.在现在的高级语言如Python.Java都使用了垃圾回收机制,不过与Java采用的垃圾收集机制不同, ...

  5. python 垃圾回收机制

    DAY 18. python垃圾回收机制 python GC主要有三种方式 引用计数 标记清除 分代回收 其中,以引用计数为主. 18.1 引用计数(Reference Counting) <寻 ...

  6. python多线程详解 Python 垃圾回收机制

    文章目录 python多线程详解 一.线程介绍 什么是线程 为什么要使用多线程 总结起来,使用多线程编程具有如下几个优点: 二.线程实现 自定义线程 守护线程 主线程等待子线程结束 多线程共享全局变量 ...

  7. python垃圾回收机制

    python垃圾回收机制 现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄 ...

  8. 人生苦短,能让你更早下班的Python垃圾回收机制

    人生苦短,只谈风月,谈什么垃圾回收. 据说上图是某语言的垃圾回收机制... 我们写过C语言.C++的朋友都知道,我们的C语言是没有垃圾回收这种说法的.手动分配.释放内存都需要我们的程序员自己完成.不管 ...

  9. 能让你更早下班的Python垃圾回收机制

    人生苦短,只谈风月,谈什么垃圾回收. 据说上图是某语言的垃圾回收机制... 我们写过C语言.C++的朋友都知道,我们的C语言是没有垃圾回收这种说法的.手动分配.释放内存都需要我们的程序员自己完成.不管 ...

最新文章

  1. socket编码问题
  2. IndiaHacks 2016 - Online Edition (Div. 1 + Div. 2) A. Bear and Three Balls 水题
  3. pyspark 通过list 构建rdd
  4. Android开发面试题之Android四大组件
  5. java 密码生成器_Java课程设计-随机密码生成器
  6. 952开头的电话一天响两三次,不是诈骗就是推销,请问该怎么屏蔽呢?
  7. SQL实战之查找最晚入职员工的所有信息
  8. lp地址为什么位_为什么内存空间分配总是以64K为边界?
  9. Security+ 学习笔记54 安全政策
  10. unity animator 动画 结束后保持位移_Unity动画系统详解9:Target Matching是什么?
  11. 使用Scala编程计算级数
  12. Python小练习——电影数据集TMDB预处理
  13. DDR3之带宽、位宽和频率使用(MIGIP核里面的时钟结构)
  14. 广义线性模型之指数分布族期望和方差的推导
  15. 一根辣条铸就的百亿生意,卫龙是如何成龙的
  16. 如何解决“数据错误,循环冗余检查”
  17. 梅特勒-托利多 TCS-35 电子台秤
  18. TLD文件自定义标签
  19. 人工智能正在重塑人力资源的7种方式
  20. killall杀死nginx顽固进程

热门文章

  1. C# 使用 StreamReader 读取数据
  2. 大工21秋《钢筋混凝土结构课程设计》模大作业离线作业
  3. 徐州医科大学计算机专业在哪个校区,定了!徐州医科大学新校区选址东湖新城 !...
  4. 全球及中国工程起重机行业格局与十四五运营趋势研究报告2022版
  5. termux目录_Termux系列教程:新手必做的初始化配置!
  6. Word替换指定开头和结尾的文字(如字幕文件)
  7. 创建map集合的实现类添加员工和工资数据: 输出每个员工的信息和工资
  8. Java获取yyyymmddhhmmss格式时间
  9. 你真的了解Systrace吗?
  10. 怎样建设现代化养猪场?