Python内存管理机制主要包括以下三个方面:
引用计数机制
引用计数增加
1.对象被创建:x=4
2.另外的别人被创建:y=x
3.被作为参数传递给函数:foo(x)
4.作为容器对象的一个元素:a=[1, x, ‘33’]
引用计数减少
1.一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。
2.对象的别名被显式的销毁:del x ;或者del y
3.对象的一个别名被赋值给其他对象:x=789
4.对象从一个窗口对象中移除:myList.remove(x)
5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
垃圾回收机制
引用计数:
引用计数也是一种垃圾收集机制。
当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。
Python又引入了其他的垃圾收集机制来弥补引用计数的缺陷:“标记-清除“,“分代回收”两种收集技术。
标记清除 :
如果两个对象的引用计数都为1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的。
也就是说,它们的引用计数虽然表现为非0,但实际上有效的引用计数为0。
所以先将循环引用摘掉,就会得出这两个对象的有效计数。
在实际操作中,并不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。
对于副本做任何的改动,都不会影响到对象生命周期的维护。
这个计数副本的唯一作用是寻找root object集合(该集合中的对象是不能被回收的)。
当成功寻找到root object集合之后,首先将现在的内存链表一分为二,一条链表中维护root object集合,成为root链表,而另外一条链表中维护剩下的对象,成为unreachable链表。
之所以要剖成两个链表,是基于这样的一种考虑:现在的unreachable可能存在被root链表中的对象,直接或间接引用的对象,这些对象是不能被回收的,一旦在标记的过程中,发现这样的对象,就将其从unreachable链表中移到root链表中;当完成标记后,unreachable链表中剩下的所有对象就是名副其实的垃圾对象了,接下来的垃圾回收只需限制在unreachable链表中即可。
分代回收 :
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,
当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;
反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
举个例子来说明:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。
当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,
而对集合A进行垃圾回收要隔相当长一段时间后才进行,
这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。
在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,
当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
内存池机制
Python的内存机制呈现金字塔形状,-1,-2层主要有操作系统进行操作;
第0层是C中的malloc,free等内存分配和释放函数进行操作;
第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;
第3层是最上层,也就是我们对Python对象的直接操作;
image
网友评论