1.何为引用
id()方法:
id(obj, /)
Return the identity of an object.
返回一个对象的标识(地址)
This is guaranteed to be unique among simultaneously existing objects.
(CPython uses the object's memory address.)
代码:
a = 1
b = 1
print(id(a))
print(id(b))
print(a is b)
运行结果:
1410343632
1410343632
True
缓冲区:Python中对比较小的对象进行了缓存,在使用的时候会首先到缓冲池中查询,
如果有,就不再去开辟内存空间,对于int类型的数据,这个范围是-5~256
代码:
a = 1000
b = 1000
print(a is b)
问题:在cmd中执行结果为False,在pycharm中执行结果为True
原因:在cmd中编写代码,是交互式执行的,每一段代码都作为一个独立的代码块,而在编译器或记事本中
(存储为.py形式的),是脚本式执行的,一个文件作为一个代码块,在运行的时候,如果发现这个代码块中已经为这个对象
开辟过内存空间,就会直接引用它,而不会重新开辟内存空间
2.引用计数机制
引用计数:一个对象身上的引用数目
当一个对象的引用计数为0的时候,证明没有其他对象引用它,这时候就可以释放掉它占用的内存空间
,完成垃圾回收。
代码1:
from sys import getrefcount
a = 10
b = 10
print(id(a))
print(id(b))
print(getrefcount(a))#打印a的引用计数
print(getrefcount(b))#打印b的引用计数
运行结果:
590126862000
590126862000
5
5
代码2:
from sys import getrefcount
print("函数执行前引用计数:{}".format(getrefcount(1000)))
def test():
a = 1000
print("函数中引用计数:{}".format(getrefcount(1000)))
print("函数执行后引用计数:{}".format(getrefcount(1000)))
test()
运行结果:
函数执行前引用计数:3
函数执行后引用计数:3
函数中引用计数:4
优点:实时性,当没有人引用这个对象的时候,就会立即释放掉它占用的内存
缺点:循环引用
循环引用
代码:
a = []
b = []
a.append(b)
b.append(a)
print(a)
print(b)
运行结果:
[[[...]]]
[[[...]]]
问题:如果两个对象相互引用的话,那么即使没有外部对象引用他们,他们的引用计数也不为0,这就造成了
永远也无法释放他们所占空间,几乎等同于内存泄漏。
3.标记-清除
标记 - 清除:
为了解决循环引用的问题,python采用了标记-清除的垃圾回收机制,当两个对象引用计数都为1,但是他们之间
只存在相互的引用,这时候我们就认为这两个对象没有被外部对象引用,可以将他们占用的内存空间释放
过程:如果A,B相互引用,那么从A的角度来看,他有一个对B的引用,所以将B的引用计数-1,反过来,B有一个对A的引用
所以A的引用也-1。
优点:
可以解决循环引用的问题
问题:
如果A对B有一个引用,但是B对A没有引用,这时候采用标记-清除机制,A和B的引用计数都-1,A可以正常回收内存
但是,B 会因此有一个悬空引用。
循环垃圾回收器:
垃圾回收机制中专门负责确保释放循环引用对象。
4.内存结构
内存池:
用户管理小块内存的申请和释放
小块内存:小于256b
小块内存申请时,PyMem_Malloc直接在内存池中申请内存
大于256b时,会调用malloc方法
网友评论