python内存管理
引用计数
python引用机制
python动态类型–》引用和对象分离
对象是存储在内存中的实体
对象–》一种数据结构–》存储对象类型、对象数值、引用计数(计算对象被引用了几次,在哪些地方被引用了)
引用计数的作用
统计有哪些变量引用指向了当前对象
当有新的引用指向的时候,引用计数+1
当有无效的引用发生的时候,引用计数-1
当对象的引用计数为0的时候,会被销毁
getrefcount能够获取对象的引用计数(比实际值多一)
>>> from sys import getrefcount
>>> a=500
>>> getrefcount(a)
2
此处500的引用计数为2,是因为getrefcount会创建一个临时的引用指向500这个对象,当getrefcount执行完以后就会自动删掉这个临时的引用
>>> b=a
>>> getrefcount(a)
3
>>> lst=[a] #列表为可变数据类型放的都是引用
>>> getrefcount(a)
4
del–删除变量的引用
>>> del a
>>> getrefcount(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> getrefcount(b)
3
引用计数的弊端:引用计数可以解决大部分内存释放问题,但是无法解决循环引用问题
>>> x=[1]
>>> y=[2]
>>> x.append(y)
>>> getrefcount(y)
3
>>> y.append(x)
>>> getrefcount(x)
3
>>> x
[1, [2, [...]]]
>>> y
[2, [1, [...]]]
>>> del x
>>> del y
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> y
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
删除x,y引用计数都减1,但是没有归0,在内存中就不会释放,程序又不能访问这片空间,造成内存泄露。使用其他的内存管理模式-------垃圾回收
垃圾回收
回收原则
当python的某个对象的引用计数降为0时,可以被垃圾回收
gc机制
GC--------现代编程语言的自动内存管理机制。
作用------找到内存中无用的垃圾资源
清除这些垃圾并把内存让出来给其他对象使用。
效率问题
垃圾回收时,python不能进行其他的任务。频繁的垃圾回收会大大降低python的工作效率
>>> import gc
>>> gc.get_threshold()
(700, 10, 10)
>>> gc.collect()
2
700表明当垃圾回收的分配对象和取消分配对象(del、a=b)的差值达到700时,垃圾回收机制才会启动。
三种情况触发垃圾回收
1.调用gc.collect()
2.GC达到阈值时
3.程序退出时
引用计数无法解决循环引用的问题那就使用垃圾回收处理
垃圾回收: 1、找到垃圾 2、回收垃圾
1、找垃圾 ---- 分代回收
2、清除垃圾 ---- 标记清除 ---- 清除循环引用的垃圾
分代回收
存活时间越久的对象,越不可能成为垃圾。
分代回收一共有三代成员:
1,2,3,4,5,6,7,8,9---------------新建对象 : 0代成员
每一次垃圾回收的时候,都会被检查
3,4,5,6---------------1代长老
在0代成员被扫描10次垃圾回收后,依然存活-----1代长老
0代扫描10次,才会扫描一次1代成员
5,6-------------------2代长老
当1代成员被扫面10次依然存活就会被标注为2代成员
1代扫描10次以后才会扫描一次2代
标记清除
标记对象,清除垃圾
主要用于解决循环引用
1.标记:活动(有被引用),非活动(可被删除)
2.清除:清除所有非活动的对象
内存泄漏:(占着茅坑不拉屎) 有一部分内存无法被释放,进程又无法访问
内存溢出OOM:(out of memory) 内存不够用,程序需要的内存大于系统空闲内存
内存池机制
整数对象缓存池:
>>> a=1
>>> b=2
>>> from sys import getrefcount
>>> getrefcount(a)
801
>>> getrefcount(b)
101
>>> c=200
>>> getrefcount(c)
3
>>> d=500
>>> f=500
>>> getrefcount(d)
2
>>> getrefcount(f)
2
>>> g=1
>>> getrefcount(g)
802
>>> h=1
>>> getrefcount(h)
803
>>> id(g)
139685766129568
>>> id(h)
139685766129568
>>> id(f)
139685766788080
>>> id(d)
139685766788112
a=1、g=1、h=1指向同一个1
d=500、f=500指向不同的500
原因:内存池机制,小整型数会有一个小整数池(-5~256)
当解释器运行起来以后会在内存空间里面开辟一段空间作为一个小整数池
当创建对象时会先看对象的数值在不在小整数池里,如果在就直接指向内存池对于的空间,否则单独开辟一段空间让对象指向这段空间。
字符串驻留区:
内存开辟一段空间用作字符串驻留区,当定义一个字符串时,先看字符串驻留区里是否已经存在。如果存在则直接引用指向,不存在则创建然后添加到驻留区。
>>> str1="abc"
>>> str2="abc"
>>> id(str1)
139685767591224
>>> id(str2)
139685767591224
>>> str1 is str2
True
字符串中如果有特殊字符则不会放到驻留区。单个特殊字符可以放到驻留区
>>> str1="abc "
>>> str2="abc "
>>> id(str1)
139685766975360
>>> id(str2)
139685767008584
>>> str1="$"
>>> str2="$"
>>> id(str1)
139685767256304
>>> id(str2)
139685767256304
总结
python内存管理------引用计数为主,分代回收和标记清除为辅的垃圾回收方式进行内存回收管理,还引用了小整型缓冲池以及常用字符串驻留区的方式进行内存管理