90%的人不懂!Python 垃圾回收机制与原理解析,原来是这样的。

Python del语句原理与内存管理实战指南 Python内存管理基于引用计数机制,del语句通过解除变量绑定直接影响对象生命周期。作为垃圾回收的关键操作,del在释放大内存对象、管理循环引用等场景具有独特技术价值。理解del与remove()/pop()的本质区别,能有效避免科学计算、Web服务等场景的内存泄漏问题。本文结合NumPy数组、pandas DataFrame等热门前沿技术,剖析del在容器操作、资源释放中的工程实践技巧,并对比分析weakref、contextlib等替代方案的适用场景。掌握这些核心知识,可显著提升数据处理效率和系统稳定 阅读详情

3031f15e17a97a6f6684b0edb7267376.png

作者:钱魏Way

来源:https://www.biaodianfu.com/garbage-collector.html

大家好,我是安果!

Python 作为一门解释型语言,以代码简洁易懂著称,我们可以直接对名称赋值,而不必声明类型,名称类型的确定、内存空间的分配与释放都是由 Python 解释器在运行时进行的

Python 这一自动管理内存功能极大的减小了程序员负担

对于 Python 这种高级别的语言,开发者完成可以不用关心其内部的垃圾回收机制,相辅相成的通过学习 Python 内部的垃圾回收机制,并了解其原理,可以使得开发者能够更好的写代码,更加 Pythonista

目录

  1. Python 内存管理机制

  2. Python 的垃圾回收机制

        2.1 引用计数(reference counting)

        2.2 标记清除(Mark and Sweep)

        2.3 分代回收(Generational garbage collector)

  1. Python 中的 gc 模块

Python内存管理机制

在 Python 中,内存管理涉及到一个包含所有 Python 对象和数据结构的私有堆(heap)。这个私有堆的管理由内部的 Python 内存管理器(Python memory manager) 保证。Python 内存管理器有不同的组件来处理各种动态存储管理方面的问题,如共享、分割、预分配或缓存。

在最底层,一个原始内存分配器通过与操作系统的内存管理器交互,确保私有堆中有足够的空间来存储所有与 Python 相关的数据。在原始内存分配器的基础上,几个对象特定的分配器在同一堆上运行,并根据每种对象类型的特点实现不同的内存管理策略。例如,整数对象在堆内的管理方式不同于字符串、元组或字典,因为整数需要不同的存储需求和速度与空间的权衡。因此,Python 内存管理器将一些工作分配给对象特定分配器,但确保后者在私有堆的范围内运行。

Python 堆内存的管理是由解释器来执行,用户对它没有控制权,即使他们经常操作指向堆内内存块的对象指针,理解这一点十分重要。

4d130e3751e9fdb396ab4d20ddc7cef3.png

Python为了避免对于小对象(<=512bytes)出现数量过多的GC,导致的性能消耗。Python对于小对象采用子分配 (内存池) 的方式进行内存块的管理。对于大对象使用标准C中的allocator来分配内存。

Python对于小对象的allocator由大到小分为三个层级:arena、pool、block。

Block

Block是最小的一个层级,每个block仅仅可以容纳包含一个固定大小的Python Object。大小从8-512bytes,以8bytes为步长,分为64类不同的block。

Request in bytesSize of allocated blocksize class idx
1-880
9-16161
17-24242
25-32323
33-40404
41-48485
………
505-51251263

Pool

Pool具有相同大小的block组成集合称为Pool。通常情况下,Pool的大小为4kb,与虚拟内存页的大小保存一致。限制Pool中block有固定的大小,有如下好处是: 当一个对象在当前Pool中的某个block被销毁时,Pool内存管理可以将新生成的对象放入该block中。

/* Pool for small blocks. */
struct pool_header {
    union { block *_padding;
            uint count; } ref;          /* number of allocated blocks    */
    block *freeblock;                   /* pool's free list head         */
    struct pool_header *nextpool;       /* next pool of this size class  */
    struct pool_header *prevpool;       /* previous pool       ""        */
    uint arenaindex;                    /* index into arenas of base adr */
    uint szidx;                         /* block size class index        */
    uint nextoffset;                    /* bytes to virgin block         */
    uint maxnextoffset;                 /* largest valid nextoffset      */
};

具有相同大小的Pool通过双向链表来连接,sidx用来标识Block的类型。arenaindex标识当前Pool属于哪个Arena。ref.conut标识当前Pool使用了多少个Block。freeblock:标识当前Pools中可用block的指针。freeblock实际是单链表实现,当一块block为空状态时,则将该block插入到freeblock链表的头部。

每个Pool都有三个状态:

  • used:部分使用,即Pool不满,也不为空

  • full:满,即所有Pool中的Block都已被分配

  • empty:空, 即所有Pool中的Block都未被分配

usedpool为了很好的高效的管理Pool,Python额外使用了array,usedpool来管理。即如下图所示,usedpool按序存储着每个特性大小的Pool的头指针,相同大小的Pool按照双向链表来连接。当分配新的内存空间时,创建一个特定大小的Pool,只需要使用usedpools找到头指针,遍历即可,当没有内存空间时,只需要在Pool的双向链表的头部插入新的Pool即可。

d83b7b72b1668d6d3f6ba02882413303.png

Arena

Pools和Blocks都不会直接去进行内存分配(allocate), Pools和Blocks会使用从arena那边已经分配好的内存空间。Arena:是分配在堆上256kb的块状内存,提供了64个Pool。

1fe5e58b0ac71ef15e3c32e97f973f1e.png
struct arena_object {
    uintptr_t address;
    block* pool_address;
    uint nfreepools;
    uint ntotalpools;
    struct pool_header* freepools;
    struct arena_object* nextarena;
    struct arena_object* prevarena;
};

所有的arenas也使用双链表进行连接(prevarena, nextarena字段). nfreepools和ntotalpools存储着当前可用pools的信息。freepools指针指向当前可用的pools。arena结构简单,职责即为按需给pools分配内存,当一个arena为空时,则将该arena的内存归还给操作系统。

Python的垃圾回收机制

Python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。

引用计数(reference counting)

Python语言默认采用的垃圾收集机制是“引用计数法 Reference Counting”,该算法最早George E. Collins在1960的时候首次提出,50年后的今天,该算法依然被很多编程语言使用。

引用计数法的原理是:每个对象维护一个ob_ref字段,用来记录该对象当前被引用的次数,每当新的引用指向该对象时,它的引用计数ob_ref加1,每当该对象的引用失效时计数ob_ref减1,一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。

它的缺点是需要额外的空间维护引用计数,这个问题是其次的,不过最主要的问题是它不能解决对象的“循环引用”,因此,也有很多语言比如Java并没有采用该算法做来垃圾的收集机制。

Python中一切皆对象,也就是说,在Python中你用到的一切变量,本质上都是类对象。实际上每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数器ob_refcnt,程序在运行的过程中会实时的更新ob_refcnt的值,来反映引用当前对象的名称数量。当某对象的引用计数值为0,说明这个对象变成了垃圾,那么它会被回收掉,它所用的内存也会被立即释放掉。

typedef struct _object {
    int ob_refcnt;//引用计数
    struct _typeobject *ob_type;
} PyObject;

导致引用计数+1的情况:

  • 对象被创建,例如a=23

  • 对象被引用,例如b=a

  • 对象被作为参数,传入到一个函数中,例如func(a)

  • 对象作为一个元素,存储在容器中,例如list1=[a,a]

导致引用计数-1的情况

  • 对象的别名被显式销毁,例如del a

  • 对象的别名被赋予新的对象,例如a=24

  • 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)

  • 对象所在的容器被销毁,或从容器中删除对象

我们可以通过sys包中的getrefcount()来获取一个名称所引用的对象当前的引用计。sys.getrefcount()本身会使得引用计数加一.

循环引用

引用计数的另一个现象就是循环引用,相当于有两个对象a和b,其中a引用了b,b引用了a,这样a和b的引用计数都为1,并且永远都不会为0,这就意味着这两个对象永远都不会被回收了,这就是循环引用 , a与b形成了一个引用循环 , 示例如下 :

a = [1, 2]  # 计数为 1
b = [2, 3]  # 计数为 1
a.append(b)  # 计数为 2
b.append(a)  # 计数为 2
del a  # 计数为 1
del b  # 计数为 1

除了上述两个对象互相引用之外 , 还可以引用自身 :

list3 = [1,2,3]
list3.append(list3)

循环引用导致变量计数永不为 0,造成引用计数无法将其删除。

引用计数法有其明显的优点,如高效、实现逻辑简单、具备实时性,一旦一个对象的引用计数归零,内存就直接释放了。不用像其他机制等到特定时机。将垃圾回收随机分配到运行的阶段,处理回收内存的时间分摊到了平时,正常程序的运行比较平稳。引用计数也存在着一些缺点:

  • 逻辑简单,但实现有些麻烦。每个对象需要分配单独的空间来统计引用计数,这无形中加大的空间的负担,并且需要对引用计数进行维护,在维护的时候很容易会出错。

  • 在一些场景下,可能会比较慢。正常来说垃圾回收会比较平稳运行,但是当需要释放一个大的对象时,比如字典,需要对引用的所有对象循环嵌套调用,从而可能会花费比较长的时间。

  • 循环引用。这将是引用计数的致命伤,引用计数对此是无解的,因此必须要使用其它的垃圾回收算法对其进行补充。

也就是说,Python 的垃圾回收机制,很大一部分是为了处理可能产生的循环引用,是对引用计数的补充。

标记清除(Mark and Sweep)

Python采用了“标记-清除”(Mark and Sweep)算法,解决容器对象可能产生的循环引用问题。(注意,只有容器对象才会产生循环引用的情况,比如列表、字典、用户自定义类的对象、元组等。而像数字,字符串这类简单类型不会出现循环引用。作为一种优化策略,对于只包含简单类型的元组也不在标记清除算法的考虑之列)

跟其名称一样,该算法在进行垃圾回收时分成了两步,分别是:

  • 标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达;

  • 清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收。

对象之间会通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从root object出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达(unreachable)的对象就是要被清除的非活动对象。所谓 root object,就是一些全局变量、调用栈、寄存器,这些对象是不可被删除的。

e54806038b49d34b71f48f9b9b083ec9.png

我们把小黑圈视为 root object,从小黑圈出发,对象 1 可达,那么它将被标记,对象 2、3可间接可达也会被标记,而 4 和 5 不可达,那么 1、2、3 就是活动对象,4 和 5 是非活动对象会被 GC 回收。

如下图所示,在标记清除算法中,为了追踪容器对象,需要每个容器对象维护两个额外的指针,用来将容器对象组成一个双端链表,指针分别指向前后两个容器对象,方便插入和删除操作。Python解释器(Cpython)维护了两个这样的双端链表,一个链表存放着需要被扫描的容器对象,另一个链表存放着临时不可达对象。

在图中,这两个链表分别被命名为“Object to Scan”和“Unreachable”。图中例子是这么一个情况:link1,link2,link3组成了一个引用环,同时link1还被一个变量A(其实这里称为名称A更好)引用。link4自引用,也构成了一个引用环。

从图中我们还可以看到,每一个节点除了有一个记录当前引用计数的变量ref_count还有一个gc_ref变量,这个gc_ref是ref_count的一个副本,所以初始值为ref_count的大小。

096a63821d83e677e6caf651392e08f0.png

gc启动的时候,会逐个遍历“Object to Scan”链表中的容器对象,并且将当前对象所引用的所有对象的gc_ref减一。(扫描到link1的时候,由于link1引用了link2,所以会将link2的gc_ref减一,接着扫描link2,由于link2引用了link3,所以会将link3的gc_ref减一…..)像这样将“Objects to Scan”链表中的所有对象考察一遍之后,两个链表中的对象的ref_count和gc_ref的情况如下图所示。这一步操作就相当于解除了循环引用对引用计数的影响。

1629a5ebf63def654e0aaa26eb602b09.png

接着,gc会再次扫描所有的容器对象,如果对象的gc_ref值为0,那么这个对象就被标记为GC_TENTATIVELY_UNREACHABLE,并且被移至“Unreachable”链表中。下图中的link3和link4就是这样一种情况。

5f04c9f733a5bf983cd89357d426835f.png

如果对象的gc_ref不为0,那么这个对象就会被标记为GC_REACHABLE。同时当gc发现有一个节点是可达的,那么他会递归式的将从该节点出发可以到达的所有节点标记为GC_REACHABLE,这就是下图中link2和link3所碰到的情形。

690f5d15b04e7bb27f15f455aa9ae8dc.png

除了将所有可达节点标记为GC_REACHABLE之外,如果该节点当前在“Unreachable”链表中的话,还需要将其移回到“Object to Scan”链表中,下图就是link3移回之后的情形。

ad7d9c1281626c2b0b16b6307da97853.png

第二次遍历的所有对象都遍历完成之后,存在于“Unreachable”链表中的对象就是真正需要被释放的对象。如上图所示,此时link4存在于Unreachable链表中,gc随即释放之。

上面描述的垃圾回收的阶段,会暂停整个应用程序,等待标记清除结束后才会恢复应用程序的运行。

标记清除的优点在于可以解决循环引用的问题,并且在整个算法执行的过程中没有额外的开销。缺点在于当执行标记清除时正常的程序将会被阻塞。另外一个缺点在于,标记清除算法在执行很多次数后,程序的堆空间会产生一些小的内存碎片。

分代回收(Generational garbage collector)

分代回收技术是上个世纪80年代初发展起来的一种垃圾回收机制,也是Java 垃圾回收的核心算法。分代回收是基于这样的一个统计事实,对于程序,存在一定比例的内存块的生存周期比较短;而剩下的内存块,生存周期会比较长,甚至会从程序开始一直持续到程序结束。

生存期较短对象的比例通常在 80%~90% 之间。因此,简单地认为:对象存在时间越长,越可能不是垃圾,应该越少去收集。这样在执行标记-清除算法时可以有效减小遍历的对象数,从而提高垃圾回收的速度,是一种以空间换时间的方法策略。

  • Python 将所有的对象分为 0,1,2 三代;

  • 所有的新建对象都是 0 代对象;

  • 当某一代对象经历过垃圾回收,依然存活,就被归入下一代对象。

那么,按什么标准划分对象呢?是否随机将一个对象划分到某个代即可呢?答案是否定的。实际上,对象分代里头也是有不少学问的,好的划分标准可显著提升垃圾回收的效率。

8cfac86e2c8570e57adcaeb234b8a057.png

Python 内部根据对象存活时间,将对象分为 3 代,每个代都由一个 gc_generation 结构体来维护(定义于 Include/internal/mem.h):

struct gc_generation { 
    PyGC_Head head; 
    int threshold; /* collection threshold */ 
    int count; /* count of allocations or collections of younger generations */ 
};

其中:

  • head,可收集对象链表头部,代中的对象通过该链表维护

  • threshold,仅当 count 超过本阀值时,Python 垃圾回收操作才会扫描本代对象

  • count,计数器,不同代统计项目不一样

Python 虚拟机运行时状态由 Include/internal/pystate.h 中的 pyruntimestate 结构体表示,它内部有一个 _gc_runtime_state ( Include/internal/mem.h )结构体,保存 GC 状态信息,包括 3 个对象代。这 3 个代,在 GC 模块( Modules/gcmodule.c ) _PyGC_Initialize 函数中初始化:

struct gc_generation generations[NUM_GENERATIONS] = {
    /* PyGC_Head, threshold, count */
    {{{_GEN_HEAD(0), _GEN_HEAD(0), 0}}, 700 0},
    {{{_GEN_HEAD(1), _GEN_HEAD(1), 0}}, 10, 0},
    {{{_GEN_HEAD(2), _GEN_HEAD(2), 0}}, 10, 0},
};

为方便讨论,我们将这 3 个代分别称为:初生代、中生代 以及 老生代。当这 3 个代初始化完毕后,对应的 gc_generation 数组大概是这样的:

4f6371b4f9f68e41ab749aa8ed28b351.png

每个 gc_generation 结构体链表头节点都指向自己,换句话说每个可收集对象链表一开始都是空的,计数器字段 count 都被初始化为 0,而阀值字段 threshold 则有各自的策略。这些策略如何理解呢?

  • Python 调用 _PyObject_GC_Alloc 为需要跟踪的对象分配内存时,该函数将初生代 count 计数器加1,随后对象将接入初生代对象链表,当 Python 调用 PyObject_GC_Del 释放垃圾对象内存时,该函数将初生代 count 计数器,1,_PyObject_GC_Alloc 自增 count 后如果超过阀值(700),将调用 collect_generations 执行一次垃圾回收( GC )。

  • collect_generations 函数从老生代开始,逐个遍历每个生代,找出需要执行回收操作(,count>threshold )的最老生代。随后调用 collect_with_callback 函数开始回收该生代,而该函数最终调用 collect 函数。

  • collect 函数处理某个生代时,先将比它年轻的生代计数器 count 重置为 0,然后将它们的对象链表移除,与自己的拼接在一起后执行 GC 算法,最后将下一个生代计数器加1。

于是:

  • 系统每新增 701 个需要 GC 的对象,Python 就执行一次 GC 操作

  • 每次 GC 操作需要处理的生代可能是不同的,由 count 和 threshold 共同决定

  • 某个生代需要执行 GC ( count>hreshold ),在它前面的所有年轻生代也同时执行 GC

  • 对多个代执行 GC,Python 将它们的对象链表拼接在一起,一次性处理

  • GC 执行完毕后,count 清零,而后一个生代 count 加 1

下面是一个简单的例子:初生代触发 GC 操作,Python 执行 collect_generations 函数。它找出了达到阀值的最老生代是中生代,因此调用 collection_with_callback(1),1 是中生代在数组中的下标。

b1cfc628a8606d64396f1e31e28217dd.png

collection_with_callback(1) 最终执调用 collect(1) ,它先将后一个生代计数器加一;然后将本生代以及前面所有年轻生代计数器重置为零;最后调用 gc_list_merge 将这几个可回收对象链表合并在一起:

4f7721c56f04c4d9c229692e678b80a5.png

最后,collect 函数执行标记清除算法,对合并后的链表进行垃圾回收。

749bca3190d8477cc5ddc027d224ccb1.png

这就是分代回收机制的全部秘密,它看似复杂,但只需略加总结就可以得到几条直白的策略:

  • 每新增 701 个需要 GC 的对象,触发一次新生代 GC

  • 每执行 11 次新生代 GC ,触发一次中生代 GC

  • 每执行 11 次中生代 GC ,触发一次老生代 GC (老生代 GC 还受其他策略影响,频率更低)

  • 执行某个生代 GC 前,年轻生代对象链表也移入该代,一起 GC

  • 一个对象创建后,随着时间推移将被逐步移入老生代,回收频率逐渐降低

Python 中的 gc 模块

gc 模块是我们在Python中进行内存管理的接口,一般情况Python程序员都不用关心自己程序的内存管理问题,但是有的时候,比如发现自己程序存在内存泄露,就可能需要用到gc模块的接口来排查问题。

有的 Python 系统会关闭自动垃圾回收,程序自己判断回收的时机,据说 instagram 的系统就是这样做的,整体运行效率提高了10%。

常用函数:

  • set_debug(flags) :设置gc的debug日志,一般设置为gc.DEBUG_LEAK可以看到内存泄漏的对象。

  • collect([generation]) :执行垃圾回收。会将那些有循环引用的对象给回收了。这个函数可以传递参数,0代表只回收第0代的的垃圾对象、1代表回收第0代和第1代的对象,2代表回收第0、1、2代的对象。如果不传参数,那么会使用2作为默认参数。

  • get_threshold() :获取gc模块执行垃圾回收的阈值。返回的是个元组,第0个是零代的阈值,第1个是1代的阈值,第2个是2代的阈值。

  • set_threshold(threshold0[, threshold1[, threshold2]) :设置执行垃圾回收的阈值。

  • get_count() :获取当前自动执行垃圾回收的计数器。返回一个元组。第0个是零代的垃圾对象的数量,第1个是零代链表遍历的次数,第2个是1代链表遍历的次数。

参考链接:

  • 聊聊Python内存管理 (https://andrewpqc.github.io/2018/10/08/python-memory-management/)

  • gc — 垃圾回收器接口 (https://docs.python.org/zh-cn/3/library/gc.html)

我们开了一个“菜鸟玩转服务器”星球

最近搞了一个阿里云的白领服务器的活动,很多同学拿了服务器之后不知道怎么玩。好比你买了一台车,但是不会开只能停在停车场太浪费了。

74bff506bd15085140b41903b7f319ea.png

于是我们开了教大家玩转云服务器,主要教大家玩Linux,安装Python,安装数据库,用Django+uwsigi+nginx web服务搭建网站,求职简历网站搭建,写脚本部署股票基金机器人,还可以搭建个人网盘!

星球的价格是一年88元,算下来每个月7块钱,连半杯奶茶的钱都不到,一天才2毛多钱,非常划算。

5e2dfed404e405f1410da3cd548045a7.png

推荐阅读:
入门: 最全的零基础学Python的问题  | 零基础学了8个月的Python  | 实战项目 |学Python就是这条捷径
干货:爬取豆瓣短评,电影《后来的我们》 | 38年NBA最佳球员分析 |   从万众期待到口碑扑街!唐探3令人失望  | 笑看新倚天屠龙记 | 灯谜答题王 |用Python做个海量小姐姐素描图 |碟中谍这么火,我用机器学习做个迷你推荐系统电影
趣味:弹球游戏  | 九宫格  | 漂亮的花 | 两百行Python《天天酷跑》游戏!
AI: 会做诗的机器人 | 给图片上色 | 预测收入 | 碟中谍这么火,我用机器学习做个迷你推荐系统电影
小工具: Pdf转Word,轻松搞定表格和水印! | 一键把html网页保存为pdf!|  再见PDF提取收费! | 用90行代码打造最强PDF转换器,word、PPT、excel、markdown、html一键转换 | 制作一款钉钉低价机票提示器! |60行代码做了一个语音壁纸切换器天天看小姐姐!|
MoveIt!核心原理与工程实践:ROS机械臂运动规划全解析 运动规划是机器人自主操作的基础能力,涉及运动学建模、碰撞检测、路径优化与实时控制等多个技术层次。其核心原理在于将任务目标转化为满足关节限位、避障约束和动力学可行性的时空轨迹。MoveIt!作为ROS生态中最成熟的运动规划中间件,通过标准化接口整合OMPL规划器、FCL碰撞检测和TF坐标变换等关键技术,显著降低机械臂应用开发门槛。它既支持Python快速原型验证,也提供C++高实时性接口,并以move_group节点为调度中枢,统一管理规划、感知与执行链路。在工业分拣、服务机器人、焊接装配等场景中,MoveI 阅读详情

相关推荐

Python数据结构底层原理与工程避坑指南

Python数据结构是支撑高效、稳定程序运行的底层基石,其行为由CPython内存模型、哈希机制、引用计数与垃圾回收等核心原理共同决定。理解list动态扩容如何实现O(1)均摊插入、tuple不可变性为何保障字典键安全性、dict紧凑存储如何带来插入有序,不仅能规避RuntimeError和None误赋值等高频bug,更能指导日志解析、订单簿维护、配置同步等真实场景的结构选型。本文聚焦可变默认参数、is/==语义差异、deepcopy递归陷阱、weakref内存控制等典型问题,结合CPython源码级分析与

weixin_33709219的博客 505

Python垃圾回收机制详解

我们从三个方面来了解一下Python的垃圾回收机制。一、引用计数   Python垃圾回收主要以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_ref,用来记录当前对象被引用的次数,也就是来追踪到底有多少引用指向了这个对象,当发生以下四种情况的时候,该对象的引用计数器+1  与上述情况相对应,当发生以下四种情况时,该对象的引用计数器-1下面来补充一下它的源码分析: Python里面每一个东西都是对象,他们的核心是一个结构体Py_Object,所有Python对象的头部包含了这样一个结构P

2301_76965813的博客 4791

bbs.rar,关于垃圾回收分类django框架的应用,

关于垃圾回收分类django框架的应用,对数据库mysql,sqlite,orm的使用进行了更为详细,更加深入的了解

一文读懂Python垃圾回收机制【收藏版】

得益于的自动垃圾回收机制,在中创建对象时无须手动释放。这对开发者非常友好,让开发者无须关注低层内存管理。但如果对其垃圾回收机制不了解,很多时候写出的代码会非常低效。垃圾回收算法有很多,主要有:、、等。引用计数原理比较简单:在中,可以通过模块的函数获取指定对象的引用计数器的值,我们以实际例子来看。 运行上面代码,可以得到输出结果为。上面我们看到,创建一个对象,并将对象赋值给变量后,对象的引用计数器值为。那么什么时候计数器会,什么时候计数器会呢?为了更好的理解计数器的增减,我们运行实际代码,一目了然。 输出结果

huachao1001的专栏 5180

从传统扫描到SSN:Tessent数据包技术如何减少90%测试时间

本文深入探讨了Tessent流式扫描网络(SSN)如何通过其核心的数据包技术,彻底改变芯片测试范式。该技术将测试数据封装成标准化数据包,在共享总线上进行智能路由与分发,实现了动态带宽分配与核心独立测试,从而将复杂SoC(如AI芯片)的总体测试时间大幅削减90%,并显著提升测试灵活性与可扩展性。

meat5的博客 491

SuperPoint + LightGlue实战:低纹理墙面重建保姆级教程(附完整代码)

本文提供了一份针对低纹理墙面三维重建的实战教程。通过详细解析SuperPoint与LightGlue的核心参数调优,指导读者如何有效提取并匹配低纹理目标的特征点,并结合COLMAP完成从稀疏到稠密的重建流程,最终实现高精度建模。

weixin_29034963的博客 223

Python 的垃圾回收机制(GC-GarbageCollection)

总体来说,在Python中,主要通过引用计数进行垃圾回收;通过 “标记-清除” 解决容器对象可能产生的循环引用问题;通过 “分代回收” 以空间换时间的方法提高垃圾回收效率。

TFATS的博客 2808

DOORS需求管理实战:从汽车设计案例看模块化需求拆分技巧

本文通过一个汽车设计实战案例,深入解析了如何利用DOORS进行模块化需求拆分与管理。从捕获原始用户需求到精炼为可追踪的系统需求,再到按子系统(如自动驾驶)进行模块化拆分,文章详细展示了构建需求骨架、建立可追溯性以及实施变更控制的完整流程,帮助团队在复杂系统工程中实现从混沌到秩序的高效协同。

ww90123的博客 244

【python】python的垃圾回收机制(详细讲解)

在大多数情况下,不需要关心Python的垃圾收集机制,因为它会自动地在后台工作。但如果你在编写大型的或内存密集的程序,理解垃圾收集机制有助于更好地管理内存。这个周期性垃圾收集器是在引用计数的基础上运行的,并且它只处理可能引起循环引用的对象。这种处理机制更加复杂,需要花费更多的计算资源,因此Python不会频繁地运行它,而是在一定的时间间隔后运行。

测试开发自动化 2372

读书笔记:深度学习入门-基于python的理论与实现(俗称鱼书)

终于从头到尾把鱼书看完啦,真的是非常入门,非常查漏补缺,对新手很友好,对有一定基础的人也非常不错。看完不复习等于没看,所以今天开始复盘,顺便写这篇读书笔记。希望分享给没看过这本书或者看过这本书的同僚们参考,欢迎大家指教。我将从第三章神经网络开始复习,前两章内容书里已经非常基础and清楚了。(会持续更新滴).........

博客而已 1万+

Mediapipe手势识别实战——基于关节角度计算实现动态手势分类

本文详细介绍了如何利用Mediapipe进行手势识别,通过计算手指关节弯曲角度实现动态手势分类。文章从基础原理出发,讲解了关节角度计算的数学方法,并提供了Python实现代码。同时,还分享了数字手势和OK手势的识别实战经验,以及性能优化和工程实践中的关键技巧,帮助开发者快速掌握实时手势识别技术。

weixin_26891599的博客 403

Python关于垃圾回收机制

Python的垃圾回收机制以引用计数为主,标记清除和分代回收为辅。引用计数可以实时回收不再使用的对象,而分代回收则负责处理循环引用,并按代管理对象以提高效率。在大多数情况下,开发者无需关心垃圾回收,但在处理循环引用或性能敏感场景时,了解这些机制有助于优化程序。

m0_64408930的博客 5175

9 HAL库驱动框架简述(STM32HAL库)

HAL库外设的使用步骤总结如下:1、定义并填充xxx外设句柄结构体。2、如果遵循HAL库规范,通过HAL_xxx_MspInit()函数,实现外设底层资源的初始化,包括但不限于GPIO、时钟、DMA、中断等资源的初始化。3、调用HAL库的对应外设初始化函数,形如:HAL_xxx_Init()。4、初始化完成,开始使用外设。5、使用方法具体查看对应外设的HAL库驱动包中的说明:补充:HAL库使用主线外设初始化外设使用。

qq_25218501的博客 1982

90%的人不懂,Python 垃圾回收机制与原理解析,原来是这样的

Python 作为一门解释型语言,以代码简洁易懂著称,我们可以直接对名称赋值,而不必声明类型,名称类型的确定、内存空间的分配与释放都是由 Python 解释器在运行时进行的 Python 这一自动管理内存功能极大的减小了程序员负担 对于 Python 这种高级别的语言,开发者完成可以不用关心其内部的垃圾回收机制,相辅相成的通过学习 Python 内部的垃圾回收机制,并了解其原理,可以使得开发者能够更好的写代码,更加 Pythonista 目录 Python 内存管理机制 Python 的垃圾回收机制

xx_nm98的博客 338

使用 Visual Studio Code 搭建 SAP UI5 本地开发环境

工欲善其事,必先利其器。时至今日,SAP 提供了非常多的 SAP UI5 开发工具,既包含本地搭建的,也包含浏览器里远端使用的工具,比如 WebIDE 和 Business Application Studio. 我们访问下面这个链接,就能找到所有这些工具的安装或者配置步骤: https://tools.hana.ondemand.com/#sapui5 如果想选择本地开发,SAP 推荐的工具是 Visual Studio Code,也就是本文要介绍的内容。 也可以下载 WebIDE 的本地安装包,将其安

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1万+

基于深度学习的茶叶等级检测识别系统:YOLOv8 + UI界面 + 数据集完整实现

随着深度学习技术的不断进步,基于计算机视觉的茶叶等级检测系统可以大大提高检测效率,提供客观一致的评估标准。本系统将利用YOLOv8进行茶叶等级的检测与识别,通过图形用户界面(UI)实现与用户的交互,提供茶叶等级分类的实时反馈。本文将详细介绍如何使用YOLOv8结合UI界面,建立一个完整的茶叶等级检测与识别系统,包括数据集的准备、模型的训练、UI的设计及完整的代码实现。本系统的目标是通过深度学习技术,结合YOLOv8模型和图形用户界面(UI),实现对茶叶等级的自动化检测与识别。

YOLO 972

python 垃圾回收机制(GC)

垃圾回收作用 垃圾回收机制可以回收不使用的变量值所占用的空间,释放空间,达到空间重复使用的目的 程序运行过程中会申请大量的内存空间,但当程序运行时并不是所有空间都可以被使用,如果不及时回收内存空间会导致内存空间用尽(内存溢出),导致程序崩溃,垃圾回收机制就是用来解决这一问题。 垃圾回收机制原理 概述 Python 的 GC(Garbage Collection) 模块主要运用了引用计数来跟踪和回收垃圾;通过“标记-清除”解决容器对象可能产生的循环引用问题;通过分代回收以空间换时间进一步提高垃圾回收

qq_46342265的博客 848

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

图解Python垃圾回收机制:引用计数 vs 分代回收

本文深入解析了Python的垃圾回收机制,重点对比了引用计数和分代回收两种策略。Python主要采用引用计数管理内存,通过对象头部的引用计数器实时跟踪引用关系,当计数归零时立即回收对象。这种机制具有实时性优势,但无法处理循环引用问题。为此,Python引入分代回收作为补充,基于"大多数对象很快消亡"的代际假说,将对象分为三代(年轻代、中年代和老年代),采用标记-清除算法定期回收不可达对象。文章通过代码示例、数学公式和结构图解,详细展示了这两种机制的工作原理及协同方式,帮助开发者深入理解P

闲人编程的博客 1258

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Python内存管理:引用计数与垃圾回收机制详解

内存管理是编程语言的核心机制之一,Python通过引用计数和垃圾回收实现自动内存管理。引用计数通过跟踪对象引用数实现即时回收,而垃圾回收则解决循环引用问题。理解这些机制对优化Python程序性能至关重要,特别是在处理大数据或长时间运行服务时。Python的分代垃圾回收策略基于对象生命周期特征,有效平衡了内存回收效率与性能开销。掌握内存管理原理有助于开发者避免内存泄漏,提升应用性能,这也是Python在数据处理、Web开发等领域广泛应用的基础保障。

weixin_30314813的博客 421

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

面试官问:垃圾回收机制是怎样的?(附图解+比喻+避坑指南)

摘要:垃圾回收(GC)是JVM自动管理内存的核心机制,自动回收不再使用的对象,避免内存泄漏。GC机制分为垃圾判定(可达性分析)、回收算法(标记-清除/复制/标记-整理/分代收集)、垃圾收集器(Serial/Parallel/CMS/G1/ZGC)三层。本文用“城市环卫系统”比喻 + 四大算法详解 + 七大收集器对比 + 6道面试官追问,彻底讲透这道JVM面试必考题。一句话:GC = 自动识别“垃圾” + 高效清理“垃圾”,让程序员从手动内存管理中解放出来。

折哥|智能物流与Java实战,副高数据库工程师。深耕出版社物流WMS/OMS(线体/立库/VGA),也分享Java进阶与OMS电商对接。Oracle→PG实战派。相信沉淀可迁移能力,分享通用技术,不藏不虚。 729

为什么你的Python服务越来越慢?90%的人都忽略了缓存过期清理策略

掌握Python缓存过期清理策略,有效解决服务性能下降问题。适用于高频读写场景,通过定时清理和LRU算法释放内存,提升系统响应速度。避免内存泄漏导致的卡顿崩溃,让应用持久高效运行,值得收藏。

Instrulink的博客 675

DOCR垃圾回收原理与安全清理实战指南

容器镜像仓库的垃圾回收(Garbage Collection)本质是基于内容寻址存储(CAS)的不可达对象识别机制,其核心依赖Docker Registry v2协议定义的manifest、config、layer三层原子结构及严格的引用可达性分析。不同于文件系统删除,GC通过反向追踪所有存活tag所关联的manifest链路,标记被直接或间接引用的数据块,仅清理真正‘不可达’的layer blob。该机制保障了K8s按digest拉取等生产场景的稳定性,但也带来误删风险与存储延迟释放等工程挑战。本文结合D

congju3179的博客 468

反软上限树G-2的垃圾回收机制:从原理到工程实践

在数据库与存储引擎领域,数据结构的设计深刻影响着系统的读写性能与扩展性。传统平衡树与B+树在处理海量数据的高并发写入和范围查询时,常面临维护开销与性能波动的挑战。其核心原理在于通过精细的节点容量管理与异步整理策略,在写入吞吐与查询效率间取得平衡。这一设计具有显著的技术价值,能够为时序数据库、OLAP系统等写入密集且需高效范围扫描的场景提供可预测的高性能。具体到反软上限树(ISUB Tree),其G-2变体通过引入代际划分与多阶段垃圾回收(gc1~gc4),实现了数据的渐进式整理与空间回收。其中,gc1负责基

weixin_33968104的博客 1381

边缘Python部署太慢?3个被90%工程师忽略的编译级加速技巧,今天必须掌握!

边缘Python部署太慢?本文提供高效边缘Python部署教程,聚焦嵌入式/IoT场景,详解交叉编译优化、精简运行时打包、字节码预编译三大编译级加速技巧,显著提升启动与执行速度。值得收藏!

LogicGap的博客 210

Python核心机制深度解析:从__new__到GIL的底层原理与应用

在Python编程中,理解对象创建、内存管理和并发机制是构建健壮应用的基础。对象创建通过__new__和__init__方法实现两步构造,这是理解单例模式和不可变类型定制的关键。内存管理依赖引用计数、标记-清除和分代回收三层机制,其中标记-清除算法专门处理循环引用问题,而gc模块提供了诊断工具。描述符协议通过__get__、__set__等方法实现了属性访问的精细化控制,是@property等装饰器的底层支撑。GIL全局解释器锁作为CPython的内存安全机制,深刻影响着多线程并发模型,需要根据I/O密集与

weixin_32247165的博客 273

Java垃圾回收原理与G1调优实战:从分代假设到线上OOM诊断

垃圾回收(GC)是Java内存管理的核心机制,其本质基于分代假设——新对象大多短命、老对象倾向长期存活。这一统计规律催生了新生代与老年代的划分,以及复制、标记-整理等差异化回收算法。现代JVM如G1通过Region化堆、可预测停顿和混合回收,在吞吐与延迟间取得平衡;而ZGC虽追求亚毫秒停顿,却受限于内存开销与JDK兼容性。理解GC不仅关乎参数配置,更需读懂日志、识别晋升异常、规避Metaspace溢出等典型陷阱。本文聚焦真实生产场景,覆盖G1参数计算逻辑、Mixed GC触发条件、GC日志三步破译法及三次O

B1334628598的博客 393
上一篇: 想搬去苏州生活了。。
下一篇: 神器!微软发布 Python 的 JIT 编译器:Pyjion!
菜鸟学Python
博客等级 码龄9年 8063粉丝 571原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值