原标题:Python内存管理机制(广州中软卓越)
python的内存管理分为三个方面:引用计数、垃圾回收、内存池机制。python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
1、引用计数增加的情况:
①对象被创建:x=4
②另外的别人被创建:y=x
③被作为参数传递给函数:foo(x)
④作为容器对象的一个元素:a=[1,x,’33’]
2、引用计数减少情况
①一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。
②对象的别名被显式的销毁:del x ;或者del y
③对象的一个别名被赋值给其他对象:x=789
④对象从一个窗口对象中移除:myList.remove(x)
⑤窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
3、对象池
python为了优化速度,使用对象池来避免频繁的申请与销毁内存空间。
a.小整数池:[-5,257)、单个字符提供对象池,常驻内存。
b.每一个大整数,均创建一个新的对象
c.对于字符串,单个单词(只有字母的字符串),不可修改,默认开启intern机制,采用引用计数机制共用对象,引用计数为0则销毁
4、垃圾回收gc(Garbage collection)
python的垃圾回收机制以引用计数为主,标记-清除和分代收集为辅。
①引用计数
优点:“实时性”,任何内存,一旦没有指向它的引用,就会立即被回收。
缺点:
(1)效率底下:引用计数机制带来的计数操作,与引用赋值成正比。频繁的技术操作,会给CPU带来大量消耗。
(2)循环引用:也就是两个对象相互引用,这样的话,两个对象的引用计数永远不会为0,及它们永远不被清除。
②标记-清除
标记-清除是为了解决循环引用的问题。可以包含其他对象引用的容器对象(比如:list,set,dict,class,instance)都可能产生循环引用。
2.1 假设
如果两个对象的引用计数都为1的话,但仅仅存在它们之间的相互引用,那么,我们可以认为这两个对象的实际引用计数为0.如果我们将这个引用循环去掉,那么它们的实际引用计数才会显现。
案例:有循环引用的A,B两个对象,从A出发,因为它有一个对B的引用,则将B的引用计数减1;然后顺着引用达到B,因为B有一个对A的引用,同样将A的引用减1,这样,就完成了循环引用对象间环摘除。
问题:如果A,B间没有循环引用,但A引用了B,B没有以用A,贸然的将B计数引用减1,而A没有被回收,这将导致在未来的某个时刻出现一个对B的悬空引用,类似与C的空指针异常。这就要求我们必须在A没有被删除的情况下复原B的引用计数,那么维护引用计数的复杂度将成倍增加。
2.2 标记-清除的原理
原理:
我们并不改动真实的引用计数,而是将集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副本做任何的改动,都不会影响到对象生命走起的维护。
这个计数副本的唯一作用是寻找root object集合(该集合中的对象是不能被回收的)。当成功寻找到root object集合之后,首先将现在的内存链表一分为二,一条链表中维护root object集合,成为root链表,而另外一条链表中维护剩下的对象,成为unreachable链表。之所以要剖成两个链表,是基于这样的一种考虑:现在的unreachable可能存在被root链表中的对象,直接或间接引用的对象,这些对象是不能被回收的,一旦在标记的过程中,发现这样的对象,就将其从unreachable链表中移到root链表中;当完成标记后,unreachable链表中剩下的所有对象就是名副其实的垃圾对象了,接下来的垃圾回收只需限制在unreachable链表中即可。
效率分析:
从垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
③分代回收
3.1 理论:
无论使用何种语言开发,无论开发的是何种类型,何种规模的程序,都存在这样一点相同之处。即:一定比例的内存块的生存周期都比较短,通常是几百万条机器指令的时间,而剩下的内存块,起生存周期比较长,甚至会从程序开始一直持续到程序结束。
3.2 原理:
将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。也就是符合马太福音,存活久的让它继续存活下去。