美文网首页
2018-08-12 python内存管理

2018-08-12 python内存管理

作者: maple_yang | 来源:发表于2018-08-12 21:39 被阅读0次

python内存管理

1. 引用和对象

  我们先看这样一个赋值语句 a=1

  在 python 中,整数 1 为一个对象,而 a 是一个引用 a→1

  Python是动态类型的语言(动态类型),对象与引用分离。Python通过引用来操作对象。

  在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用。

# id()是Python内置的函数,它用于返回对象的身份(identity),也就是内存地址。
# hex 返回一个数的十六进制表示
a = 1
b = 1
print(id(1))
print(id(a))
print(id(b))
print(hex(id(a)))
1644917568
1644917568
1644917568
0x620b7340

  从上边代码的输出可以看出,a 和 b 其实是指向同一个对象的两个引用。

  我们现在使用 is 来检测一下,整数和短小的字符指的是什么。

a = 1
b = 1
print(a is b)
True
a = 'good'
b = 'good'
print(a is b)
True
a = 'good night'
b = 'good night'
print(a is b)
print(a[:4] is 'good')
print(a[:4] is b[:4])
False
False
False
a = [1]
b = [1]
print(a is b)
False

  可以看到,python缓存了整数和短小的字符,所以指向它们的引用都是指向的缓存好的对象。

  对于较长的字符,则是另外分配的内存,即使是相同的字符串的引用,由于它们指向的对象是另外分配的内存,它们的内存地址也是不同的。

a = 'good night'
b = 'good night'
print(hex(id(a)))
print(hex(id(b)))
0x19b922e1070
0x19b922e17b0
a 和 b 指向的内存

  在 Python 中,每个对象都有指向该对象的引用计数。我们可以使用 sys.getrefcount() 来查看某个对象的引用计数,参数传递给 getrefcount()时,会创建一个临时的引用,所以 getrefcount() 会比期望结果多 1。

import sys
a = [1, 2]
sys.getrefcount(a)
2

  Python 中的容器对象,如 list、tuple、dict 等,可以包含多个对象。实际上,它们包含的只是对象的引用而已。

a = [1, 2]
b = [a]
print(b)
[[1, 2]]
a[0] = -1
print(b)
[[-1, 2]]

  使用 del 可以删除一个引用,同时也会减少相应对象的引用计数。此外,将引用指向别的对象也会使引用计数减少。

a = [1]
b = a
c = b
print( sys.getrefcount(c) )
del a # del 删除变量,减少引用计数
print( sys.getrefcount(c) )
b = None # 指向别的对象,减少引用计数
print( sys.getrefcount(c) )
4
3
2

  两个对象还可以相互引用,这样会形成一个引用环。

a = [1]
b = [a]
a.append(b)
print(a)
[1, [[...]]]

  一个对象也有可能会形成引用环。

a = [1]
a.append(a) # 如果是 a = [a],则不会形成引用环,此时 a 为 [[1]]
print(a)
[1, [...]]

2.垃圾回收

  当Python中的对象越来越多,它们将占据越来越大的内存,这个时候就需要垃圾回收(Garbage Collection)了。当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。

  不过,垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。如果内存中的对象不多,就没有必要总启动垃圾回收。所以,Python只会在特定条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。我们可以通过gc模块的get_threshold()方法,查看该阈值:

import gc
print(gc.get_threshold())
(700, 10, 10)

  后面的两个10是与分代回收相关的阈值。700即是垃圾回收启动的阈值,可以通过 gc.set_threshold() 方法重新设置。另外,还可以手动回收gc.collect()

  另外,引用环会给 GC 带来很大的麻烦。对于上面提到的一个对象引用环的情况,即使删除了引用 a ,list 对象的引用计数也不会为0。


单对象引用环

  Python 采用了分代回收的策略。这一策略的基本假设是,存活时间越久的对象,越不可能在后面的程序中变成垃圾。我们的程序往往会产生大量的对象,许多对象很快产生和消失,但也有一些对象长期被使用。出于信任和效率,对于这样一些“长寿”对象,我们相信它们的用处,所以减少在垃圾回收中扫描它们的频率。

  Python将所有的对象分为0,1,2三代。所有的新建对象都是0代对象。当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象。垃圾回收启动时,一定会扫描所有的0代对象。如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。

  这两个次数即上面get_threshold()返回的(700, 10, 10)返回的两个10。也就是说,每10次0代垃圾回收,会配合1次1代的垃圾回收;而每10次1代的垃圾回收,才会有1次的2代垃圾回收。

  另外,引用环会给 GC 带来很大的麻烦。

a = [1]
a.append(a) # 如果是 a = [a],则不会形成引用环,此时 a 为 [[1]]
print(a)
[1, [...]]

  对于上面提到的一个对象引用环的情况,即使删除了引用 a ,list 对象的引用计数也不会为0,不会被垃圾回收。


单对象引用环

  为了回收这样的引用环,Python复制每个对象的引用计数,可以记为 gc_ref。假设,每个对象 i,该计数为 gc_ref_i。Python 会遍历所有的对象 i。对于每个对象 i 引用的对象 j,将相应的 gc_ref_j 减 1。在结束遍历后,gc_ref 不为0的对象,和这些对象引用的对象,以及继续更下游引用的对象,需要被保留。而其它的对象则被垃圾回收。


解决引用环

  下面例子中 a 指向的对象的引用计数为 2(=3-1),在去除引用 a 后变为 1,由于对象引用了本身,所以它的引用计数应该减一,即 gc_ref = 0,这表明改对象应该被垃圾回收。

a = [1]
a.append(a) # 如果是 a = [a],则不会形成引用环,此时 a 为 [[1]]
print(a)
print(sys.getrefcount(a))
[1, [...]]
3

参考链接:http://www.cnblogs.com/vamei/p/3232088.html

相关文章

  • 2018-08-12 python内存管理

    python内存管理 1. 引用和对象   我们先看这样一个赋值语句 a=1   在 python 中,整数 1 ...

  • python内存管理机制

    Python内存管理机制 Python内存管理机制主要包括以下三个方面: 引用计数机制 垃圾回收机制 内存池机制 ...

  • 深入理解Python内存管理与垃圾回收,再也不怕问了(一)

    面试官:听说你学Python?那你给我讲讲Python如何进行内存管理? 我:???内存管理不太清楚额。。。 面试...

  • python内存释放

    Python内存释放 python话说会自己管理内存,实际上,对于占用很大内存的对象,并不会马上释放。举例,a=r...

  • 新手上路?八大秘术助你offer无数(Python初学者/码农必

    话不多说,干货: 1、Python是如何进行内存管理的? Python的内存管理主要有三种机制:引用计数机制、垃圾...

  • 面试日记--python的内存管理

    面试中被问到python的内存管理,只是说是python有自己的内存管理机制,有自己的垃圾回收机制,却不能详细作答...

  • Python基础知识

    一、Python简介 Python 是一种解释型语言,在 Python 中,由于内存管理是由 Python ...

  • python(Class7)

    内存管理之循环引用 在Python3.x中,内存管理问题基本上不会出现,类似与OC中的ARC机制在Python2....

  • Python3学习 - 第二节

    为什么说Python采用的是基于值的内存管理模式? Python采用的是基于值的内存管理方式,如果为不同变量赋相同...

  • iOS ARC

    内存管理 引用计数:Objective-C Python 垃圾收集:C#,Java等 区别 内存管理的基本规则 自...

网友评论

      本文标题:2018-08-12 python内存管理

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