目录
百战程序员,全站22050+开发课程+文档 ,学习精选优质好课快人一步!观看视频 快捷键ALT+N

Python全系列 教程

3567个小节阅读:5931.2k

收藏
全部开发者教程

鸿蒙应用开发

C语言快速入门

JAVA全系列 教程

面向对象的程序设计语言

Python全系列 教程

Python3.x版本,未来主流的版本

人工智能 教程

顺势而为,AI创新未来

大厂算法 教程

算法,程序员自我提升必经之路

C++ 教程

一门通用计算机编程语言

微服务 教程

目前业界流行的框架组合

web前端全系列 教程

通向WEB技术世界的钥匙

大数据全系列 教程

站在云端操控万千数据

AIGC全能工具班

A

A A

White Night

阅读(1k)
赞(0)

标记-清除

引用计数法能够解决大多数垃圾回收的问题,但是遇到两个对象相互引用的情况,del语句可以减少引用次数,但是引用计数不会归0,对象也就不会被销毁,从而造成了内存泄漏问题。针对该情况,Python引入了标记-清除机制

循环引用

image-20220530155815008

引用计数这种管理内存的方式虽然很简单,但是有一个比较大的瑕疵,即它不能很好的解决循环引用问题。如上图所示:对象 A 和对象 B,相互引用了对方作为自己的成员变量,只有当自己销毁时,才会将成员变量的引用计数减 1。因为对象 A 的销毁依赖于对象 B 销毁,而对象 B 的销毁与依赖于对象 A 的销毁,这样就造成了我们称之为循环引用(Reference Cycle)的问题,这两个对象即使在外界已经没有任何指针能够访问到它们了,它们也无法被释放。

上述实例中,对象p中的属性引用c,而对象c中属性同时来引用p,从而造成仅仅删除p和c对象,也无法释放其内存空间,因为他们依然在被引用。深入解释就是,循环引用后,p和c被引用个数为2,删除p和c对象后,两者被引用个数变为1,并不是0,而python只有在检查到一个对象的被引用个数为0时,才会自动释放其内存,所以这里无法释放p和c的内存空间。

主动思路一般分为两步:垃圾识别垃圾回收 。垃圾对象被识别出来后,回收就只是自然而然的工作了,因此垃圾识别是解决问题的关键。那么,有什么办法可以将垃圾对象识别出来呢?我们来考察一个一般化例子:

图片描述

这是一个对象引用关系图,其中灰色部分是需要回收但由于循环引用而无法回收的垃圾对象,绿色部分是被程序引用而不能回收的活跃对象。如果我们能够将活跃对象逐个遍历并标记,那么最后没有被标记的对象就是垃圾对象。

遍历活跃对象,第一步需要找出 根对象 ( root object )集合。所谓根对象,就是指被全局引用或者在栈中引用的对象,这部对象是不能被删除的。因此,我们将这部分对象标记为绿色,作为活跃对象遍历的起点。

图片描述

根对象本身是 可达的 ( reachable ),不能删除;被根对象引用的对象也是可达的,同样不能删除;以此类推。我们从一个根对象出发,沿着引用关系遍历,遍历到的所有对象都是可达的,不能删除。

图片描述

这样一来,当我们遍历完所有根对象,活跃对象也就全部找出来了:

图片描述

而没有被标色的对象就是 不可达 ( unreachable )的垃圾对象,可以被安全回收。循环引用的致命缺陷完美解决了!

图片描述

这就是垃圾回收中常用的 标记清除法

【示例】标记清除法

image-20220417123205186

上图中小黑点(变量)表示根节点,从根节点出发,每个对象都有引用和被引用的情况,如果该对象找不到根节点,那么就会被清除,如图1,2,3都有被小黑点(变量)引用,4,5没有变量引用,所以4,5就会被清除。

实时效果反馈

1. 由于_____的存在,就算我们将外部变量删除,对象的引用计数也不为零,无法回收。

A 引用计数

B 内部循环引用

2. 引用计数法能够解决大多数垃圾回收的问题,但是遇到两个对象相互引用的情况,del语句可以减少引用次数,但是引用计数不会归0,对象也就不会被销毁,从而造成了内存泄漏问题。针对该情况,Python引入了_______

A 引用计数机制

B 标记-清除机制

C 分代回收机制

D 对象跟踪

答案

1=>B 2=>B

 

北京市昌平区回龙观镇南店村综合商业楼2楼226室

©2014-2023 百战卓越(北京)科技有限公司 All Rights Reserved.

京ICP备14032124号-2