Python with 工作原理、装饰器、回收机制、内存管理机制、拷贝、作用域等(11)


定义了两个变量x = 10、y = 20
当我们执行x=y时 , 内存中的栈区与堆区变化如下:
标记 / 清除算法的做法是当应用程序可用的内存空间被耗尽的时 , 就会停止整个程序 , 然后进行两项工作 , 第一项则是标记 , 第二项则是清除 。
通俗地讲就是:标记的过程就行相当于从栈区出发一条线 , “连接”到堆区 , 再由堆区间接“连接”到其他地址 , 凡是被这条自栈区起始的线连接到内存空间都属于可以访达的 , 会被标记为存活 。
具体地:标记的过程其实就是 , 遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象) , 然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象 , 其余的均为非存活对象 , 应该被清除 。
直接引用指的是从栈区出发直接引用到的内存地址 , 间接引用指的是从栈区出发引用到堆区后再进一步引用到的内存地址 , 以我们之前的两个列表l1与l2为例画出如下图像:
当我们同时删除l1与l2时 , 会清理到栈区中l1与l2的内容:
这样在启用标记清除算法时 , 发现栈区内不再有l1与l2(只剩下堆区内二者的相互引用) , 于是列表1与列表2都没有被标记为存活 , 二者会被清理掉 , 这样就解决了循环引用带来的内存泄漏问题 。
垃圾回收机制:分代回收
分代回收是一种以空间换时间的操作方式 , 将内存根据对象的存活时间划分为不同的集合 , 每个集合称为一个代 , 将内存分为了3“代” , 分别为年轻代(第0代)、中年代(第1代)、老年代(第2代) , 他们对应的是3个链表 , 它们的垃圾收集频率与对象的存活时间的增大而减小 。新创建的对象都会分配在年轻代 , 年轻代链表的总数达到上限时(当垃圾回收器中新增对象减去删除对象达到相应的阈值时) , 垃圾收集机制就会被触发 , 把那些可以被回收的对象回收掉 , 而那些不会回收的对象就会被移到中年代去 , 依此类推 , 老年代中的对象是存活时间最久的对象 , 甚至是存活于整个系统的生命周期内 。同时 , 分代回收是建立在标记清除技术基础之上 。
事实上 , 分代回收基于的思想是 , 新生的对象更有可能被垃圾回收 , 而存活更久的对象也有更高的概率继续存活 。因此 , 通过这种做法 , 可以节约不少计算量 , 从而提高的性能 。
所以对于刚刚的问题 , 引用计数只是触发gc的一个充分非必要条件 , 循环引用同样也会触发 。
垃圾回收机制:调试
可以使用 来调试程序 , 因为目前它的官方文档 , 还没有细读 , 只能把文档放在这供大家参阅啦~其中两个函数非常有用 1. () 2. ()
垃圾回收机制:总结
垃圾回收是自带的机制 , 用于自动释放不会再用到的内存空间;
引用计数是其中最简单的实现 , 不过切记 , 这只是充分非必要条件 , 因为循环引用需要通过不可达判定 , 来确定是否可以回收;
的自动回收算法包括标记清除和分代回收 , 主要针对的是循环引用的垃圾收集;
调试内存泄漏方面 , 是很好的可视化分析工具 。
10、内存管理机制