Python垃圾回收机制及内存管理
内存管理:
先定义一个变量 name=‘wxl’
那么python会在内存中开辟一小块区域存放“wxl",此时变量的值是我们真正想要存储的,wxl指向了name。那么我们通过name就可以找到“wxl”.当wxl捆绑着name时,wxl这个变量就不算垃圾。反过来就可以理解:当一个变量值没有捆绑变量名时,占用了内存空间,这个变量名就是垃圾。
引用计数:以wxl为例,变量值身上捆绑了几个变量名,就是被引用了几次,引用计数就为几。
上图这种情况意味着被引用了三次,引用计数为3.当变量值的引用计数为0时 也就是说不能通过任何一个变量名找到变量值,他此时就为垃圾。
现有如下操作:
name=wxl;
y=name;
x=name;
在此之前我们会认为变量xy等于name.当我们了解内存管理机制后,我们可以这样理解:变量值在内存中申请一小块空间存放wxl,并指向name。二三步操作也是指向变量名xy而已。并不是我们所认为的三个变量相等。若有:del x操作,看上去是删除变量,实际上是解除变量名x与变量值wxl的绑定关系,wxl的引用计数为2;del y 操作同理。那么重新给name定义:name=12345。此时意味着wxl与z的捆绑关系解除,同时与12345进行绑定。这时候wxl的引用计数为0变成垃圾。
id不相同的情况下,值可能相同,两块不同的内存空间里可以存储相同的值。
id相同的情况下,值一定相同。
标记清除:
这里我们先介绍一个东西叫做循环引用:先定义两个列表,我们知道列表在内存空间存储时,内部存储的其实是元素的地址。如图:
进行如下操作:
那么此时内存空间应该是这样:
那么如何证明L1中的111和在L2中进行添加操作的111是同一个呢?
我们只需看ID即可
既然ID相同 那么就是同一个。引用分直接引用和间接引用两种:直接引用是从栈区出发直接引用到的内存地址。
间接引用的从栈区出发引用到堆区后在进一步引用到的内存地址的操作
我们接下来删除直接引用L1 与L2 ,因为只剩下L1与L2的互相引用存在 ,他们的计数不会为0。他们是垃圾吗?肯定是 !因为他已经没有用了 而且我们不能通过任何索引找到他们,但他们确确实实还是存在,因此这就是循环引用。因为每一个对象的引用计数不为0,所以他们所占用的内存永远不会被释放。
基于这种问题python引入标记清除和分代回收:
在上图中可以看到内存分为堆区和栈区:栈区是用来存放变量名和值内存地址的关联的,堆区是用来存放变量值;而内存管理对应的是堆区。当内存被耗尽时,python会停止程序来扫瞄空间,
标记过程中,先遍历所有的对象(栈区内的所有内容和线程),然后将可以通过直接引用和间接引用的对象的堆区对象进行标记,其余未标记的堆区对象就应该被清除。
请除过程中,清除所有的未标记的对象。