day35-猴子补丁和垃圾回收机制

2020-08-25  本文已影响0人  天行_b6d0

一、猴子补丁

首先,顾名思义,补丁就是原有的程序出现了什么小的漏洞或者缺失需要补上的新功能,就像过去衣服破了一小块舍不得扔又找一小块布把漏洞补上一样。猴子补丁拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)。因为这样的补丁容易把原来的代码搞乱,像猴子一样调皮捣乱,所以叫做猴子补丁。

二、垃圾回收机制

1、什么是垃圾回收机制

垃圾回收机制(简称GC)是Python解释器自带一种机制,专门用来回收不可用的变量值所占用的内存空间。

2、为什么要使用垃圾回收机制

程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来。

3、垃圾回收机制原理

​ Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题,并且通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。

3.1 引用计数

引用计数就是:变量值被变量名关联的次数,某个值的内存地址被关联一次,它的引用计数就加一。
一般来说,某个值引用计数一旦变为0,其占用的内存地址就应该被解释器的垃圾回收机制回收。

3.2 引用计数存在的问题
(1)循环引用

举个例子:

l1 = ["xxx",[l2]]
l2 = ["yyy",[l1]]

这个时候就出现了循环引用,循环引用会导致:值不再被任何名字关联,但是值的引用计数并不会为0,应该被回收但不能被回收。
当执行:

del l1
del l2

此时,只剩下列表1与列表2之间的相互引用,但此时两个列表的引用计数均不为0,但两个列表不再被任何其他对象关联,没有任何人可以再引用到它们,所以它俩占用内存空间应该被回收,但由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放,所以循环引用是致命的,这与手动进行内存管理所产生的内存泄露毫无区别。 所以Python引入了“标记-清除” 与“分代回收”来分别解决引用计数的循环引用与效率低的问题。

(2)循环引用的解决方法:标记清除

容器对象(比如:list,set,dict,class,instance)都可以包含对其他对象的引用,所以都可能产生循环引用。而“标记-清除”计数就是为了解决循环引用的问题。

标记/清除算法的做法是当应用程序可用的内存空间被耗尽的时,就会停止整个程序,然后进行两项工作,第一项则是标记,第二项则是清除

1、标记
通俗地讲就是:
栈区相当于“根”,凡是从根出发可以访达(直接或间接引用)的,都称之为“有根之人”,有根之人当活,无根之人当死。
具体地:标记的过程其实就是,遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,其余的均为非存活对象,应该被清除。
2、清除
清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。

这样在启用标记清除算法时,从栈区出发,没有任何一条直接或间接引用可以访达l1与l2,即l1与l2成了“无根之人”,于是l1与l2都没有被标记为存活,二者会被清理掉,这样就解决了循环引用带来的内存泄漏问题。

(3)引用计数效率低

基于引用计数的回收机制,每次回收内存,都需要把所有对象的引用计数都遍历一遍,这是非常消耗时间的,于是引入了分代回收来提高回收效率,分代回收采用的是用“空间换时间”的策略。

(4)分代回收解决效率问题
上一篇 下一篇

猜你喜欢

热点阅读