39-高级特性之内存管理

1. 对象池:

  • 为了减小创建相同对象的开销,python将以下的数据类型的instance放在对象池中(常驻内存)。如果需要的对象已经创建过,就直接去池子中拿:(无须每次都创建和销毁)
  • 小整数:[-5,257) #好像有变化了
  • 单个英文字符
  • 单个单词(以空格为分界线,有空格就是一个句子)
c1 = 'a'
c2 = 'a'
print(id(c1), id(c2),'
')

d1 = -6
d2 = -6
print(id(d1), id(d2),'
')

d3 = 5
d4 = 5
print(id(d3), id(d4),'
')

d5 = 258
d6 = 258
print(id(d5), id(d5), '
')

s1 = "hello"
s2 = "hello"
s3 = "hello "#有个空格
print(id(s1), id(s1), id(s3),'
')

senten1 = "hello world"
senten2 = "hello world"
print(id(senten1), id(senten2), '
')

2. 内存管理机制:

Garbage collection(垃圾回收)

  • 为新生成的对象分配内存
  • 识别那些垃圾对象
  • 从垃圾对象那回收内存
  • python采用的是引用计数机制为主, 标记-清除和分代收集两种机制为辅的策略
  • 引用计数机制的原理(C代码)

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

typedef struct_object {
    int ob_refcnt; //referance count
    struct_typeobject *ob_type;
} PyObject; 

#define Py_INCREF(op) ((op)->ob_refcnt++)  //增加计数
#define Py_DECREF(op)                     //减少计数
if (--(op)->ob_refcnt != 0) 
    ; 
else 
    __Py_Dealloc((PyObject *)(op))
  • 引用计数的优缺点:

(1)优点:

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

(2)缺点:

  • 维护引用计数消耗资源
  • 循环引用
  • 引用计数的计数值发生变化:

(1)导致引用计数+1的情况

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

(2)导致引用计数-1的情况

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

3. 引用计数分析:

  • 查看某对象的引用计数:sys.getrefcount()

    def p(str=''):
    print(str,' ')

    import sys
    a = 100 #a是小整数,放在对象池中(被各种对象引用),因而引用计数值应该很大
    p(sys.getrefcount(a))

    b = 1000 #刚刚new了一个b指向1000所在的内存, 引用数加一,设为b0
    p(sys.getrefcount(b)) #但是刚刚把b传入getrefcount(),所以此时引用值为b0+1

    a = b #再次引用了b,引用加1,即:
    p(sys.getrefcount(b)) # b0+2

    c = [b] #再次引用了b,引用加1,即:
    p(sys.getrefcount(b)) # b0+3

    del c
    p(sys.getrefcount(b)) #b的引用应该减一
    del c
    p(sys.getrefcount(b)) #b的引用应该减一

  • 测试循环引用的影响:

    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 #发生了c1和c2的循环引用
    c2.t = c1
    del c1 #当需要删除互为循环引用的对象时,引用计数机制会出问题
    del c2

    gc.disable() #把python的gc关闭
    f2() #内存使用率会越来越大

  • 垃圾回收的时机:

  • 调用gc.collect()
  • 当gc模块的计数器达到阀值的时候。
  • 程序退出的时候
  • gc模块:
  • 垃圾回收后的对象会放在gc.garbage这个列表中
  • gc.get_threshold() 获取的gc模块中自动执行垃圾回收的频率
  • gc.set_threshold(threshold0[,threshold1[,threshold2]) 设置自动执行垃圾回收的频率
  • gc.get_count() 获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表
  • gc.collect([generation]) 显式进行垃圾回收,可以输入参数,0代表只检查第一代的对象,1代表检查一,二代的对象,2代表检查一,二,三代的对象,如果不传参数,执行一个full collection,也就是等于传2。返回不可达(unreachable objects)对象的数
  • gc模块唯一处理不了的是循环引用的类都有__del__方法,所以项目中要避免定义__del__方法
原文地址:https://www.cnblogs.com/LS1314/p/8504579.html