python进阶:垃圾回收

垃圾回收

垃圾回收一:

1.小整数对象池

整数在程序中的使用很是普遍,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。java

Python 对小整数的定义是 [-5, 257) 这些整数对象是提早创建好的,不会被垃圾回收。在一个 Python 的程序中,全部位于这个范围内的整数使用的都是同一个对象.python

同理,单个字母也是这样的。app

可是当定义2个相同的字符串时,引用计数为0,触发垃圾回收函数

2,大整数对象池

每个大整数,均建立一个新的对象。优化

 

3.intern机制

python靠引用计数去维护什么时候释放内存spa

4.总结

  • 小整数[-5,257)共用对象,常驻内存
  • 单个字符共用对象,常驻内存
  • 单个单词,不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁 
  • 字符串(含有空格),不可修改,没开启intern机制,不共用对象,引用计数为0,销毁 
  • 大整数不共用内存,引用计数为0,销毁 
  • 数值类型和字符串类型在 Python 中都是不可变的,这意味着你没法修改这个对象的值,每次对变量的修改,其实是建立一个新的对象 

垃圾回收二:

 python里也同java同样采用了垃圾收集机制,不过不同的是: python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略操作系统

引用计数机制:debug

python里每个东西都是对象,它们的核心就是一个结构体:PyObject日志

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

PyObject是每一个对象必有的内容,其中ob_refcnt就是作为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增长,当引用它的对象被删除,它的ob_refcnt就会减小;当引用计数为0时,该对象生命就结束了。 code

引用计数机制的优势:
  • 简单
  • 实时性:一旦没有引用,内存就直接释放了。不用像其余机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
引用计数机制的缺点:
  • 维护引用计数消耗资源
  • 循环引用
list1 = [] list2 = [] list1.append(list2) list2.append(list1)

ist1与list2相互引用,若是不存在其余对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远没法被回收,这将是致命的。 对于现在的强大硬件,缺点1尚可接受,可是循环引用致使内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)

GC系统所承担的工做远比"垃圾回收"多得多。实际上,它们负责三个重要任务。它们

  • 为新生成的对象分配内存
  • 识别那些垃圾对象,而且
  • 从垃圾对象那回收内存。

当建立对象时,python当即向操做系统请求内存

标记-清除:

中止程序,加标记,把未被标记的对象看成垃圾处理

垃圾回收三:gc模块

1.致使引用计数+1的状况

  • 对象被建立,例如a=23
  • 对象被引用,例如b=a
  • 对象被做为参数,传入到一个函数中,例如func(a)
  • 对象做为一个元素,存储在容器中,例如list1=[a,a]

2.致使引用计数-1的状况

  • 对象的别名被显式销毁,例如del a
  • 对象的别名被赋予新的对象,例如a=24
  • 一个对象离开它的做用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
  • 对象所在的容器被销毁,或从容器中删除对象

3.查看一个对象的引用计数

import sys y='hh'
print(sys.getrefcount(y))

4.循环引用致使内存泄露

import gc class ClassA(): def __init__(self): print('object born,id:%s'%str(hex(id(self)))) def f2(): while True: c1 = ClassA() c2 = ClassA() c1.t = c2 c2.t = c1 del c1 del c2 #把python的gc关闭
gc.disable() f2()

执行f2(),进程占用的内存会不断增大。

  • 建立了c1,c2后这两块内存的引用计数都是1,执行c1.t=c2c2.t=c1后,这两块内存的引用计数变成2.
  • 在del c1后,内存1的对象的引用计数变为1,因为不是为0,因此内存1的对象不会被销毁,因此内存2的对象的引用数依然是2,在del c2后,同理,内存1的对象,内存2的对象的引用数都是1。
  • 虽然它们两个的对象都是能够被销毁的,可是因为循环引用,致使垃圾回收器都不会回收它们,因此就会致使内存泄露。

5.什么状况下触发python垃圾回收

1).import gc 

 gc.get_threshold()

输出:(700,10,10)      (当没有释放的对象个数超过700,即开始0级垃圾回收,0级垃圾回收超过10次即开始1级垃圾回收,1级垃圾回收清除包括0级垃圾,1级垃圾回收超过10次,即开始2级垃圾回收,2级垃圾回收清除包括0级,1级垃圾)

2).垃圾回收机制python默认开启的,gc.disabled可关闭垃圾回收机制,当程序完成时,垃圾最后仍被回收

3).当gc.disabled时,gc.collect手动开启垃圾回收机制

6.gc模块经常使用功能解析

gc模块提供一个接口给开发者设置垃圾回收的选项。上面说到,采用引用计数的方法管理内存的一个缺陷是循环引用,而gc模块的一个主要功能就是解决循环引用的问题。

经常使用函数:

一、gc.set_debug(flags) 设置gc的debug日志,通常设置为gc.DEBUG_LEAK

二、gc.collect([generation]) 显式进行垃圾回收,能够输入参数,0表明只检查第一代的对象,1表明检查一,二代的对象,2表明检查一,二,三代的对象,若是不传参数,执行一个full collection,也就是等于传2。 返回不可达(unreachable objects)对象的数目

三、gc.get_threshold() 获取的gc模块中自动执行垃圾回收的频率。

四、gc.set_threshold(threshold0[, threshold1[, threshold2]) 设置自动执行垃圾回收的频率。

五、gc.get_count() 获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表

相关文章
相关标签/搜索