垃圾回收机制

垃圾回收机制

说白了就是十二个字

引用计数、标记清除、分代回收

看不懂没关系我们往下看:

【1】引用计数

Python 语言默认采用的是 引用计数 的垃圾回收机制。 该算法的原理是:每个对象维护一个 ob_ref 的字段,用来记录该对象当前被引用的次数,每当有新的引用指向该对象是,它的引用计数 ob_ref + 1,每当该对象的引用失效时,计数器 ob_ref - 1,一旦引用计数为 0,该对象立即被回收,对象占用的空间会被释放。它的缺点是需要额外的空间维护引用计数,这个问题是其次的,最主要的问题是它不能解决对象中的 "循环引用" 问题,因此,很多语言比如 java 并没有采用才算法来做垃圾的收集机制。

什么是循环-引用?A 和 B 相互引用而在外部没有引用 A B 中的任何一个,它们的引用计数虽然都为 1,但显然应该被回收:

a = {} # 对象 a 的引用计数为 1
b = {} # 对象 b 的引用计数为 1
a['b'] = b # 对象 b 的引用计数 +1 = 2
b['a'] = a # 对象 a 的引用计数 +1 = 2
del a  # a 的 ref -1,=1
def b  # b 的 ref -1,=1

事实上,Python 本身能够处理这种情况, 可以显示调用 gc.collect(),来启动垃圾回收。

import os
import psutil
import gc

# 显示当前 python 程序占用的内存大小
def show_memory_info(hint):
    pid = os.getpid()
    p = psutil.Process(pid)

    info = p.memory_full_info()
    memory = info.uss / 1024 / 1024
    print("{} memory used: {} MB".format(hint, memory))

def func_1():
    show_memory_info('initial')
    a = [i for i in range(10000000)]
    b = [i for i in range(10000000)]
    show_memory_info('after a,b created')
    a.append(b)
    b.append(a)

if __name__ == "__main__":
    # func_1()
    # show_memory_info('finished')

    func_1()
    gc.collect()
    show_memory_info('finished')

#############输出################
initial memory used: 8.49609375 MB
after a,b created memory used: 783.20703125 MB
finished memory used: 783.20703125 MB


initial memory used: 8.3984375 MB
after a,b created memory used: 783.1796875 MB
finished memory used: 8.73828125 MB

所以,Python 的垃圾回收机制并没有那么弱。

【2】标记-清除

在 Python 中,垃圾回收机制主要使用了标记清除算法(Mark and Sweep)来管理内存。Python 的标准解释器 CPython 使用了这种垃圾回收机制。

CPython 的标记清除算法工作原理如下:

  1. 标记阶段(Mark)

    • 从根对象开始,通常是全局变量、模块、当前执行堆栈等,标记所有可访问的对象。
    • 这一过程通过遍历对象之间的引用关系来实现,将可达的对象标记为活动对象。
  2. 清除阶段(Sweep)

    • 在清除阶段,Python 的垃圾回收器会遍历整个堆内存,回收未标记的对象所占用的内存空间。
    • 未被标记的对象即被视为垃圾对象,它们所占用的内存将被释放。
    • 此外,清除阶段还负责处理循环引用的情况,即相互引用但已不可达的对象。

Python 的垃圾回收机制是自动运行的,它通过引用计数和周期性的标记清除来管理内存。引用计数用于跟踪对象的引用数量,当引用计数为零时,对象即被认定为垃圾并被回收。而标记清除算法则处理循环引用等无法通过引用计数解决的情况。

需要注意的是,标记清除算法在进行垃圾回收时会导致一定的性能开销和停顿时间。为了减少这种影响,Python 也提供了其他优化技术和算法,比如分代回收(Generational Garbage Collection)和增量垃圾回收(Incremental Garbage Collection)等。

总结起来,Python 的标准解释器 CPython 使用标记清除算法来管理内存并进行垃圾回收,保证程序的内存使用效率和稳定性。

【3】分代回收

分代回收的基本思想是根据对象的存活时间将其划分为不同的代,通常将所有对象划分为三代:0代、1代和2代。新创建的对象会被放入 0 代,而经过一次垃圾回收仍然存活的对象会被提升到更高的代中。当某一代中的对象经过多次垃圾回收仍然存活下来,就可以认为它的存活概率较高,需要更少的垃圾回收操作。

Python 的分代回收主要基于以下两个原理:

  1. 弱代假设 (Weak Generational Hypothesis)

    • 大部分对象在内存中存在的时间很短,即新创建的对象往往很快就变得不可达。
    • 较早创建的对象,即存活时间较长的对象,更有可能在未来继续存活下来。
  2. 代之间的存活率关系 (Generation Survival Rate)

    • 0 代中的对象一般存活时间最短,因此需要更频繁地进行垃圾回收。
    • 1 代中的对象相对较少存活,需要相对较少的垃圾回收操作。
    • 2 代中的对象存活率更高,需要较少的垃圾回收操作。

Python 的分代回收机制会根据这些原理,定期对不同代进行垃圾回收操作。通常,每次垃圾回收后,存活的对象会被提升到更高的代中。这样一来,垃圾回收机制可以更加集中地处理那些存活时间较长的对象,从而提高垃圾回收效率。

分代回收是 Python 垃圾回收机制的重要组成部分,它通过根据对象的存活时间进行优化,提高了垃圾回收的效率和性能。这对于 Python 这种动态语言来说尤为重要,因为它经常面临着频繁的内存分配和回收操作。

要是还不懂

个人见解:

1. 如何定义垃圾数据?
    name = 'kevin'
    name = 'tank'
    
2. 如何回收、清除
	"""在Python中,已经开发了一套成熟的垃圾回收方案!"""
    1. 引用计数
    	一个变量值如果有一个变量名指向,那么,在它身上就计数1,引用计数为0的数据都为垃圾数据,我们也会把引用计数为0的数据清除点
    2. 标记清除
    	# 原来比较复杂,你只需要记住它的大致原来怎么回事就行了
        当我们的内存空间即将要沾满的时候,这个时候会暂停所有程序的执行,开始扫描内存空间中得数据,把垃圾数据进行打标签,然后统一进行垃圾数据的清除.
    3. 分代回收
    	对垃圾数据的监管频率逐渐下降
相关推荐
平头哥在等你9 分钟前
python特殊字符序列
开发语言·python·正则表达式
星光樱梦1 小时前
02. Python基础知识
python
亚图跨际1 小时前
MATLAB和C++及Python流式细胞术
c++·python·matlab·流式细胞术
steamedobun1 小时前
【爬虫】Firecrawl对京东热卖网信息爬取(仅供学习)
爬虫·python
右恩1 小时前
Docker 实践与应用举例
python·docker
凤枭香1 小时前
Python Scikit-learn简介(二)
开发语言·python·机器学习·scikit-learn
湫ccc9 小时前
《Python基础》之字符串格式化输出
开发语言·python
mqiqe10 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin10 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
哭泣的眼泪40810 小时前
解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
python·算法·django·virtualenv·pygame