美文网首页
Python36_垃圾回收

Python36_垃圾回收

作者: jxvl假装 | 来源:发表于2019-09-27 12:31 被阅读0次

注意,垃圾回收机制的测试建议以交互模式测试

ps:对于垃圾回收机制,有的python版本默认开了,有的则默认没有开

intern机制

a2 = "hello"
a3 = "hello"
a1 = "hello"
a4 = "hello"
a5 = "hello"
print(id(a1),id(a2),id(a3),id(a4),id(a5))

对于python,他有这么一个机制——intern机制,只让一个“hello”占用内存空间。靠引用计数去维护何时释放。但是应注意,字符串中不能有特殊字符,如(括号、引号、逗号、斜线、反斜线、冒号、句号、问号等等)

小整数池

对于小整数([-5,257)),python已经提前创建好了对象,他们常驻内存,采用引用计数


在这里插入图片描述

所以他们有相同的地址,属于同一个对象

对于其他整数


在这里插入图片描述

临时创建,属于不同的对象


注意

现在许多IDE都作了一些额外的改进,比如Pycharm,会发现只要是相同常量,他们的地址都相同(似乎与Java类似),但是这并不是python本身的特性


Garbage collection(GC垃圾回收)

现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄漏,悬空指针等bug埋下隐患。对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配垃圾回收内存的问题。python里也同java一样采用了垃圾收集机制,不过不一样的是:python采用的是引用计数机制为主,标记-清除和分代收集机制为辅的策略。

ps:现在常用的python解释器最初是python发明人吉多用c语言写的,称cpython。另还有java语言实现的解释器和其他语言实现的解释器

底层实现

typedef struct_object{
    int ob_refcnt;
    struct_typeobject *ob_type;
}PyObject;

PyObject是每个对象必有的内容,其中ob_refcnt就是作为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少

#define Py_INCREF(op) ((op)->ob_refcnt++)   //增加计数
#define Py_DECREF(op) \ //减少计数
    if (--(op)->ob_refcnt != 0) \
        ; \
    else \
        __Py_Dealloc((PyObject *)(op))

当引用计数为0时,该对象生命就结束了

引用计数机制的优点:

  1. 简单
  2. 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还有一个好处:处理坏收内存的时间分摊到了平时。

引用计数机制的缺点:

  1. 维护引用计数消耗内存资源
  2. 循环引用时,做占的内存永远无法被回收。会导致内存泄漏,注定python还将引入新的回收机制(标记清除和分代收集)。

循环引用示例:

list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

对于循环引用的解决:分代回收(Gerneration Zero)

  • 分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率随着对象存活时间的增大而减小。
  • 新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉(对于检测出相互引用的,另其计数器同时减1,如果发现他们减1后同时为0,则回收),而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。
  • 同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象

gc模块

import gc

常用函数

get_count()

获取当前自动执行垃圾回收器的计数器,返回一个长度为3的列表

set_threshold(threshold0[, threshold1[, threshold2]])

设置自动执行垃圾回收的频率

get_threshold()

threshold 英文意思为临界值

获取gc模块中自动执行垃圾回收的频率,返回一个元组,其3个元素分别表示在什么情况下清理0、1、2代链表,当新创建的对象减去已经释放完的对象的个数大于第一个元素的值,则触发0代的清理;每清理第二个元素次0代链表,就清理一次1代链表,第三个元素的作用类似第二个元素值。

查看与改变gc的状态

  1. 打开gc:gc.enable()
  2. 关闭gc:gc.disable()
  3. 查看gc状态:gc.isenabled()
  4. 显示回收:gc.collect(),即使是disable了,也可以显示的collect
  5. 查看刚刚清理的垃圾列表:gc.garbage,注意,是一个属性,不是方法

其他

导致引用计数+1的情况

  1. 对象被创建,eg:a = 23
  2. 对象被引用,eg:b = a
  3. 对象被作为参数,传入到一个函数中,eg:func(a)
  4. 对象作为一个元素,存储在容器中,eg:my_list = [a, a]

导致引用计数-1的情况

  1. 对象的别名被显示销毁,eg:del a
  2. 对象的别名被赋与新的对象,eg:a = 12
  3. 一个对象离开他的作用域,例如 f 函数执行完毕时,func函数中的局部变量(全局变量不会)
  4. 对象所在的容器被销毁,或从容器中删除对象

查看一个对象的引用计数

import sys
a = "hello world"
sys.getrefcount(a)  #ps,调用此函数查看计数时,会导致其计数+1,因为把a当作参数传入函数了

gc的“bug”

对于一个类,如果重写了__del__方法而没有在重写的方法中调用父类的del方法,就会出现无法清理的情况。即:如果重写了del方法,一定要在重写的方法中调用父类的del方法

相关文章

  • Python36_垃圾回收

    注意,垃圾回收机制的测试建议以交互模式测试 ps:对于垃圾回收机制,有的python版本默认开了,有的则默认没有开...

  • 简单理解垃圾回收

    什么是垃圾回收? 垃圾回收的是什么? 如何判断为垃圾? 垃圾是怎样被回收的? 垃圾回收哪些区域的内存? 什么是垃圾...

  • JVM(二) GC算法与分代回收策略

    可达性分析 GCRoot场景 垃圾回收算法 分代回收策略 引用 垃圾回收 垃圾回收(Garbage Collect...

  • JVM调优之垃圾定位、垃圾回收算法、垃圾处理器对比

    谈垃圾回收器之前,要先讲讲垃圾回收算法,以及JVM对垃圾的认定策略,JVM垃圾回收器是垃圾回收算法的具体实现,了解...

  • 01垃圾回收机制

    垃圾回收(Garbage Collection,GC) 垃圾回收就是释放垃圾占用的空间 内存的动态分配和垃圾回收,...

  • Java 垃圾收集(GC)浅谈

    Java 垃圾收集(GC)浅谈 为什么需要垃圾回收?哪些内存需要回收?什么时候回收?如何回收? 为什么需要垃圾回收...

  • JVM垃圾回收机制

    JVM垃圾回收 整体思维导图 带着问题理解JVM垃圾回收机制 Java为什么需要垃圾回收机制; 回收哪部分垃圾; ...

  • 垃圾回收

    如何查看当前JVM使用的垃圾回收器? 如何指定使用CMS回收? 如何打印回收日志? 垃圾回收过程 CMS垃圾回收的...

  • JVM常见垃圾回收器介绍

    垃圾回收器简介 在新生代和老年代进行垃圾回收的时候,都是要用垃圾回收器进行回收的,不同的区域用不同的垃圾回收器。分...

  • JavaScript的垃圾回收机制

    大纲 1、认识垃圾回收机制2、垃圾回收机制的原理3、垃圾回收机制的标记策略4、垃圾回收机制与内存管理 1、认识垃圾...

网友评论

      本文标题:Python36_垃圾回收

      本文链接:https://www.haomeiwen.com/subject/smhuuctx.html