垃圾回收机制怎么还没有回收我这个垃圾!
堆和栈
简单点说就是:栈内存由操作系统自动进行分配和释放,不需要程序员担心和管理。而堆内存是由程序员进行申请和管理的内存。
栈是一块连续的内存区域,在程序启动的时候就已经被分配确定,是一种先进后出的数据结构,每次对象被调用压入栈的时候被压入栈中,返回时被弹出。堆是非连续的内存区域,可以动态变化大小,通常用来存储动态分配的数据。
如果程序员申请了一个内存地址,而没有对它进行主动释放的话,就会一直占用该内存,影响执行效率。而垃圾回收机制就是为了解决该问题,不需要程序员在内存回收上面进行太多操作,由程序自动执行。
python的GC
python的垃圾回收机制主要是引用计数,当一个对象被引用的时候,会使该计数加一,当该对象不被使用之后,该计数减一,当一个对象的引用计数为0的时候,python会认为它已经不再被使用了,也就成为了一个垃圾对象,在内存中被删除。可以使用sys模块中的getrefcount函数来回去对象的引用计数:
1 | import sys |
引用计数的缺陷:如果出现了循环引用,或者出现了一些线程间的竞争冒险等,就有可能会导致一个对象已经完全不会再被引用,但它的计数还没有归零,这个对象就会一直占用一块内存,导致内存泄漏
为了应对上述缺陷,python中还有第二种垃圾回收算法:标记清除算法从跟对象开始对每个对象进行遍历,将所有可达的对象进行一个标记,如果一个对象不可达(孤岛),那么它就会被当做垃圾清理回收掉。该方法可以有效解决因为循环引用等产生的无法回收的内存。标记清楚的缺陷:容易产生内存碎片,一些小的内存碎片很难再次利用,且每次将所有的对象遍历会比较耗时
python中还有一种更高级的回收算法:分代回收分代回收每次进行查询的时候都会把对象归类为某一代,如新对象就是第一代,如果一个对象经常被引用的话,那么该对象的存活代数就会越来越高,分代回收算法会减少对于长高代数对象的扫描,提升了内存回收的效率。
1 | # 观察垃圾回收机制的工作过程 |
输出结果如下:
1 | 2 # 对象计数为2 |