内存管理

一、小整数池和intern机制

a = 257
b = 257
c = 10
d = 10
# 为什么 交互环境下c和d的地址一样,a和b的id地址不一样
  • 小整数池
    • Python自动将-5和256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象
a = "abc?"
b = "abc?"
c = "abc"
d = "abc"
# 为什么 交互环境下c和d的地址一样,a和b的id地址不一样
  • intern机制(数字、字符、下划线)
    • Python会将一定规则的字符传在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象,而是使用在字符串驻留池中创建好的对象
  • 其实,无论是缓存还是字符串驻留池,都是Python做的一个优化,就是将-5-256,和一定规则的字符串,放在一个池中,无论程序中哪些变量指向这些范围内的整数或者字符串,那么它直接在这个池内引用,言外之意,就是内存中创建一个
优点:能够提高一些字符串和整数处理任务时的时间和空间上的性能,需要相同整数和字符串的时候,直接在内存中取,避免频繁的创建和销毁,提升效率,节约内存

二、深浅拷贝--针对可变类型而言

  • 赋值,值发生变化互相影响
  • copy赋值,第一层不受影响,嵌套的可变类型受影响
  • deepcopy,完全赋值一份,完全不受影响
import copy

li = [1, 2, 3]
list1 = [1, 2, li]
list2 = list1
list3 = copy.copy(list1)
list4 = copy.deepcopy(list1)
list1.append(3)
print(list2)  # 赋值指向同一块内存地址,一个变都变

# 复制,重新开辟一块空间,不受list1的影响
# 但是li的地址并没有重新开辟一份空间储存还是用的li空间地址
print(list3)
li.append(4)
# list1第二层的li变了,复制的list3也会变
print(list3)
# deepcopy 不受li的影响,完完全全的复制一份,不管是嵌套的还是非嵌套的
print(list4)

三、垃圾回收和GC模块

  • 对象引用
    • 变量:通过变量指针引用对象
      • 变量指针指向具体对象的内存空间,去对象的值
    • 对象:类型已知,每个对象都包含一个头部信息
      • 头部信息: 类型标识符、引用计数
    • 上面代码中,a = 10 此时a这个变量指向10这个对象,这个10的对象头部就会计数为1,b = a ,那么此时b引用的是a这个变量,a又是指向的10这个对象,此时的b实际上也是指向的10这个对象,那么10这个对象头部计数就会是2
a = 10
b = a
# 那么此时打印b,返回的结果也是10这个对象,
# b也是对这个变量的引用
  • 垃圾回收机制
    • Python的垃圾回收机制用一句话来形容就是:引用计数为机制为主,标记-清除和分代收集两种机制为辅的策略
  • 引用计数
    • 每个对象创建之后都有一个引用计数,当引用计数为0的时候,那么此时的垃圾回收记住会自动把它销毁,回收内存空间
  • 标记-清除
    • 出现循环引用的时候,对象删除后计数还不会为0
    • 这个时候标记清除就会删除掉,没有被全局变量接收的的对象
li1 = [1, 2, 3]
li2 = [11, 22, 33]
# 循环引用,li1和li2 计数都会为2
li1.append(li2)
li2.append(li1)

del li1
del li2
# 如果只有引用计数,删除都计数只会从2变成1
# 导致数据一直在内存在
# 但是li1和li2 都被删除了此时内存的计数为1的li1和li2是没有全局变量接收的
# 此时标记-清除就会发挥功能,删除没有全局变量接收的引用对象

# 案例二
def a():
    a1=10  # 走出函数,a1没有被全局变量引用就会被标记清除
    print("")

print(a1)  # 报错


  • 分代回收

    • 将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
    • 这样的思想,可以减少标记-清除机制所带来的额外操作。隔代就是将回收对象分成数个代,每个代就是一个链表(集合),代进行标记-清除的时间与代内对象存活时间成正比例关系。
  • gc.get_threshold() # 获取分代回收的参数

    • 这个方法涉及到之前说的分代回收的策略,Python中默认把所有的对象分成三代,从第0代包含最新的对象,第2代则是最早的一些对象,在一次垃圾回收中,所有未被回收的对象被移到高一代的地方
    • 这个方法返回(700, 10, 10),这也是gc的默认值,这个值的意义是说:没在第0代对象数据达到700之前,不会把未被回收的对象放入第1代中,而在第一代对象达到10个之前也不会把未被回收的对象放到第二代中
  • gc.set_threshold()

    • 设置这个分代回收数值
posted @ 2019-05-28 01:25  讲明白  阅读(182)  评论(0编辑  收藏  举报