Python的垃圾回收机制有两种(也可以说一种:叫引用计数): 一是引用计数, 二是隔代回收.
引用计数
引用计数原理: 当数据的引用数变成0的时候,python解释器就认为这个数据是垃圾,进行垃圾回收,释放空间.
分代回收
分代回收是用来解决交叉引用(循环引用),并增加数据回收的效率. 原理: 通过对象存在的时间不同,采用不同的算法来 回收垃圾. 形象的比喻, 三个链表,零代链表上的对象(新创建的对象都加入到零代链表),引用数都是一,每增加一个指针,引用加一,随后python会检测列表中的互相引用的对象,根据规则减掉其引用计数. GC算法对链表一的引用减一,引用为0的,清除,不为0的到链表二,链表二也执行GC算法,链表三一样. 存在时间越长的数据,越是有用的数据.
标记清除
为什么python没有标记清除机制,
因为python的标记就是引用数,是模仿Ruby的标记清除机制,为什么Ruby要用标记清除机制,因为Ruby在代码开始执行之前就已经创建了成百上千个对象,对有指针的对象进行标记(这个标记是Ruby解释器制作的),没有指针的对象进行清除,并送回可用列表中,从而节约计算机资源.
标记清除是Ruby的垃圾回收机制,标记(通过M标记)可达的数据, 会清除不带M标记的数据.
如何判断对象是否存活
引用计数法给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1,如果引用失效,计数器值减1,所以当该计数器的值为0时,就表示该对象可以被回收了。但是存在两个对象之间相互循环引用的问题。
可达性分析算法
通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索的路径称为引用链,当一个对象到“GC Roots”没有任何引用链相连的话,也就是GC Roots到这个对象不可达时,证明此对象已经不可用,可以被回收了。
二次标记
在可达性分析算法中被判断是对象不可达时不一定会被垃圾回收机制回收,因为要真正宣告一个对象的死亡,必须经历两次标记的过程。如果发现对象不可达时,将会进行第一次标记,此时如果该对象调用了finalize()方法,那么这个对象会被放置在一个叫F-Queue的队列之中,如果在此队列中该对象没有成功拯救自己(拯救自己的方法是该对象有没有被重新引用),那么GC就会对F-Queue队列中的对象进行小规模的第二次标记,一旦被第二次标记的对象,将会被移除队列并等待被GC回收,所以finalize()方法是对象逃脱死亡命运的最后一次机会。
垃圾回收算法
标记—清除算法首先标记出需要回收的对象,在标记完成后进行统一的回收(标记即二次标记的过程)。此算法有两个不足:一是效率问题,标记和清除两个过程效率都不高;二是空间问题,标记清除后会产生大量不连续的内存碎片,内存空间碎片太多的话会导致以后程序在运行中想要分配较大对象的时候,无法找到一块连续的内存空间而导致不得不进行又一次的GC回收(后续的垃圾回收算法都是基于此算法进行改进的)。
标记—清除算法
复制算法
把内存按容量划分为大小相等的两块区域,每次只使用其中的一块,当这一块的内存空间用完了,就把还存活的对象复制到另一块内存中去,然后把已经使用的过的内存空间一次性清理掉。这样每次都是对半个内存区域进行GC回收,并不会产生内存碎片,但是代价是把内存缩小了一半,效率比较低。
复制算法
标记—整理算法
标记算法一样,区别是清除的时候会把所有存活的对象向一端移动(向上和向左),然后清除掉端边界以外的内存。
标记—整理算法
分代收集算法
根据对象存活周期的不同将内存划分为几块(新生代或老生代),然后根据每个年代的特点采用最合适的收集算法。比如在新生代中,每次都有大量对象死去,就选择复制算法;而在老生代中对象的生存率高,没有额外的空间为它进行分配担保,所以采用标记—清除算法或者标记—整理算法来进行回收
垃圾回收器
CMS收集器CMS收集器是一种以获取最短回收停顿时间为目标的垃圾收集器,是基于“标记——清除”算法实现的,其回收过程主要分为四个步骤:
(1)初始标记:标记一下GC Roots能直接关联到的对象,速度很快;
(2)并发标记:进行GC Roots Tracing的过程,也就是标记不可达的对象,相对耗时;
(3)重新标记:修正并发标记期间因用户程序继续运作导致的标记变动,速度比较快;
(4)并发清除:对标记的对象进行统一回收处理,比较耗时;由于初始标记和重新标记速度比较快,其它工作线程停顿的时间几乎可以忽略不计,所以CMS的内存回收过程是与用户线程一起并发执行的。
初始标记和重新标记两个步骤需要Stop the world;并发标记和并发清除两个步骤可与用户线程并发执行。
“Stop the world”意思是垃圾收集器在进行垃圾回收时,会暂停其它所有工作线程,直到垃圾收集结束为止。CMS的缺点
(1)对CPU资源非常敏感;也就是说当CMS开启垃圾收集线程进行垃圾回收时,会占用部分用户线程,如果在CPU资源紧张的情况下,会导致用户程序的工作效率下降。
(2)无法处理浮动垃圾导致又一次FULL GC的产生;由于CMS并发回收垃圾时用户线程同时也在运行,伴随用户线程的运行自然会有新的垃圾产生,这部分垃圾出现在标记过程之后,CMS无法在当次收集过程中进行回收,只能在下一次GC时在进行清除。所以在CMS运行期间要确保内存中有足够的预留空间用来存放用户线程的产生的浮动垃圾,不允许像其它收集器一样等到老年代区完全填满了之后再进行收集;那么当内存预留的空间不足时就会产生又一次的FULL GC来释放内存空间,由于是通过Serial Old收集器进行老年代的垃圾收集,所以导致停顿的时间变长了(系统有一个阈值来触发CMS收集器的启动,这个阈值不允许太高,太高反而导致性能降低)。
(3)标记——清除算法会产生内存碎片;如果产生过多的内存碎片时,当系统虚拟机想要再分配大对象时,会找不到一块足够大的连续内存空间进行存储,不得不又一次触发FULL GC。
G1收集器
G1收集器是一款成熟的商用的垃圾收集器,是基于“标记——整理”算法实现的,其回收过程主要分为四个步骤:
(1)初始标记:标记一下GC Roots能直接关联到的对象,速度很快;
(2)并发标记:进行GC Roots Tracing的过程,也就是标记不可达的对象,相对耗时 ;
(3)最终标记:修正并发标记期间因用户程序继续运作导致的标记变动,速度比较快;
(4)筛选回收:首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划;G1收集器的特点
(1)并发与并行:机型垃圾收集时可以与用户线程并发运行;
(2)分代收集:能根据对象的存活时间采取不同的收集算法进行垃圾回收;
(3)不会产生内存碎片:基于标记——整理算法和复制算法保证不会产生内存空间碎片;
(4)可预测的停顿:G1除了追求低停顿时间外,还能建立可预测的停顿时间模型,便于用户的实时监控;CMS收集器与G1收集器的区别
(1)CMS采用标记——清除算法会产生空间碎片,G1采用标记——整理算法不会产生空间碎片;
(2)G1可以建立可预测的停顿时间模型,而CMS则不能;