Python源码解读之四 对象回收与引用计数

Python基础1-2 c// 普通对象强制转PyObject*// 常量版本// 变长对象强制转PyVarObject*C 源码中通用强转工具,任意 Python 对象指针都能转回基础结构体,方便读取引用计数、长度、类型。PyObject所有对象通用头部,统一管理引用计数、类型;:在基对象基础上扩展长度字段,专门给字符串 / 列表等多元素容器使用;Python 上层所有数据类型,都是基于这两个 C 结构体封装实现,这就是 “一切皆对象” 的底层根源。 阅读详情

前言

在 C 和 C++ 中,程序员被赋予了极大的自由,可以任意地申请内存。但权力的另一面对应着责任,程序员最后不使用的时候,必须负责将申请的内存释放掉,并把无效指针设置为空。可以说,这一点是万恶之源,大量内存泄漏、悬空指针、越界访问的 bug 由此产生。

而现代的开发语言都带有垃圾回收机制,语言本身负责内存的管理和维护,比如 C#、Java、Go。垃圾回收机制将开发人员从维护内存分配和清理的繁重工作中解放出来,但同时也剥夺了程序员和内存亲密接触的机会,并牺牲了一定的运行效率。不过好处就是提高了开发效率,并降低了 bug 发生的概率。

Python 里面同样具有垃圾回收机制,只不过它是为引用计数机制服务的。所以解释器通过内部的引用计数和垃圾回收,代替程序员进行繁重的内存管理工作,关于垃圾回收我们后面会详细说,先来看一下引用计数。

引用计数

Python通过管理对象的引用计数来决定对象在内存中的存在与否,前面的分享中我们说过,Python一切皆对象,所有对象都有一个 **_ob_refcnt _**成员。这个成员维护这对象的引用计数,也决定这对象的存在与消亡。

相比起类型对象,我们更关注实例对象行为。因为只有讨论实例对象,我们的讨论才有意义。类型对象(内置)超越了引用计数规则,永远不会被析构或者销毁,因为他们在底层是被静态定义好的。同理,我们自定义的类,虽然可以被回收,但是探讨它的引用计数也是没有价值的,我们可以看第一个例子:

class A:
    pass

del A

首先 del_ **关键字只能作用于变量,不可以作用于对象,比如:pi = 3.14,你可以del pi,但是不可以 del 3.14,这不符合语法规则。因为 **del _的作用是让变量指向的对象的引用计数减 1,所以我们只能 del 变量,不能 del 对象。
我们使用 def 、class 关键字定义出来的也属于变量,比如上面代码中的 A ,只要是变量,就可以被 del。但是 del 变量只是删除了该变量,换言之就是让该变量无法再被使用,至于变量指向的对象是否会被回收,就看是否还有其他的引用也指向它。也就是说,对象是否被回收完全由解释器判断他的引用计数是否为0所决定。
因此当对象的所有引用都被删除之后,那么该对象也会被删除。以我们上面的代码为例,里面的 A 也是一个变量,引用了某个 PyTypeObject 结构体实例,并且它也纸杯变量 A 引用。所以当 del A 之后,底层的类对象也会被销毁。
另外,我们虽然说 int、str、 tuple 这些是类型对象,但这只是从 Python 的层面。如果要从解释器的角度来看,比如 int ,它也是一个变量,指向对应的数据结构(PyLong_Type),既然是变量,那么久可以被删除。

try:
    del int
except NameError as e:
    print(e) # name 'int' is not defined

上面的代码在执行的时候报错了,原因是 del 只能删除局部作用于和全局作用域内的变量(也就是局部变量和全局变量),对于内置作用域里面的变量, del 是无法删除的。

如果从底层来讲, int它也是一个变量, 指向了对应的数据结构(PyLong_Type)
既然是变量, 那么就可以删除, 但是这个删除并不是直接删除对象,而是将变量指向的对象的引用计数减去1,然后将这个变量也给删掉。
Python中的对象是否被删除是通过其引用计数是否为0决定的, "del 变量"只是删除了这个变量,让这个变量不再指向该对象罢了
所以"del 变量"得到的结果就是我们没办法再使用这个变量了,这个变量就没了,但是变量之前指向的对象是不是也没了就看还有没有其它的引用也指向它。

如果一定想删除也是有办法的,需要显式地指定内置作用域,比如:

# 内置类型、内置函数都在__builtins__ 里面
print(__builtins__) # <module 'builtins' (built-in)>
# __builtins__ 等价于 import builtins
# Python变量查找默认按照 LEGB 规则
# 所以调用 __builtins__.int 比直接用 int 要快一些

# 我们将 int 给删掉,可以直接 del __builtins__.int
# 但这里获取了模块的属性字典
# 主要想表明操作模块本质上就是操作模块的属性字典
# 比如 module.attr 相当于 module.__dict__["attr"]

__builtins__.__dict__.pop("int") # 等价于 del __builtins__.int
try:
    print(int(3))
except NameError as e:
    print(e) # name 'int' is not defined

我们看到此时 int 已经不能使用了,因为它已经从内置作用域中被删除了。不过 int 虽然被上除了,但是 int 底层指向的 PyLong_Type 却没有被删除。

del __builtins__.int

try:
    print(int(3))
except NameError as e:
    print(e)  # name 'int' is not defined

# int 虽然被删除
# 但是 int 指向的类型对象没有被删除
n = 123
print(n.__class__)  # <class 'int'>
print(n.__class__("0xFF", base=16))  # 255

之所以会有这个现象,是因为底层的 PyLong_Type 并不仅仅被 int 这个变量所引用,我们来查看一下它的引用计数吧。

import sys

print(sys.getrefcount(int))  # 98
my_int = int
print(sys.getrefcount(int))  # 99

我们看到整型对象的引用计数非常多,主语它都被谁引用了,我们就不用关心。总之,我们探讨类型独享的引用计数是没有太大意义的,而且内置类型超越了引用计数的规则,我们也没有太多关注的必要。我们得需要关注的是实例对象。

>>> import sys
>>> e = 2.71
>>> sys.getrefcount(e)
2

当我们创建一个新的对象时,引用对象应该为 1 ,但是这里为什么是 2 呢?因为 e 这个变量作为参数传到了sys.getrefcount 这个函数里面,所以函数里面的参数也指向 2.71 这个 PyFloatObject, 所以引用计数加1 。当函数结束后,局部变量被销毁,再将引用计数减 1 。

>>> a = e
>> sys.getrefcount(e)
3
>>> sys.getrefcount(a)
3

上面这段应该比较容易理解,因为变量间的传递会传递指针,所以 a 也会指向 2.71 这个浮点数,因此对象的引用计数加 1 。

注意:我们说变量只是个符号,引用计数是针对变量指向的对象而言的,变量本身没有所谓的引用计数。

此时变量 e 指向的对象的引用计数为 3 ,我们说操作变量相当于操作变量指向的对象,a e 都指向同一个对象,所以结果是一样的,都是 3 ,因为实际上获取的是同一个对象的引用计数。

>>> lst = [e, a]  
>>> sys.getrefcount(e)  
5

>>> del lst
>>> sys.getrefcount(e)  
3  

把变量放在容器里面,显然列表 lst 里面多了两个指针,这两个指针也指向这里的 PyFloatObject对象,因此结果是 5 也就不难理解了。
将列表删除、或者将列表清空,那么里面的变量也就没了。而在删除变量之后,会将变量指向的对象的引用计数减去 1,所以又变成了 3。

# 再删除一个变量,引用计数再减 1
>>> del a  
>>> sys.getrefcount(e)
2 
# 结果为 2,说明外部还有一个变量在引用它
# 所以这个浮点数不会被回收。
# 如果再次del,引用计数就会为0,这个浮点数就真的没了。
>>> del e  

另外,引用计数什么时候会加1,什么时候会减1,在上一篇文章中已经说的很详细了,可以去看一下。

这里增加一个额外的讨论,这里使用sys.getrefcount查看引用计数,为什么要用命令行。如果大家有用pycharm执行这段代码,会发现打印出来的结果是4而不是2。这里说一下在pycharm是那4个地方引用已经为什么在交互打印结果是2。
首先pycharm引用的分别是:

  1. 全局名字空间
  2. 每个编译单元都会有一个常量池(元组),存放字符串、整数浮点数等常量
  3. 解释器在编译脚本时,会将它转成字节码,这个过程也会将便连忙,以及常量都放在一个列表中
  4. sys.getrefcount是一个函数,传进去也会加一个引用

而在交互打印的结果是2,原因在于交互环境下,每一行都是一个独立的执行单元,执行之后,该单元被销毁了,只有全局名字空间会保存2.71的引用。而使用pycharm,整个文件是作为一个整体编译的。

如果在交互环境下,输入e = 2.71;sys.getrefcount(e),会发现打印的结果也是4,因为一行,查看引用计数的时候,e = 2.71所在的编译单元还没有被销毁。

在底层,解释器会通过Py_INCREF(op)和Py_DECREF(op)这两个宏,来增加和减少一个对象的引用计数,当一个对象的引用计数减少到 0 后,Py_DECREF将调用该对象的析构函数来释放该对象所占有的内存和系统资源。这个析构函数由对象的类型对象(Py***_Type)中定义的函数指针来指定,也就是tp_dealloc。
我们来看一下底层的这些宏:

#define _Py_NewReference(op) (                          \
    _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA         \
    _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA               \
    Py_REFCNT(op) = 1)
    //对于新创建的对象,引用计数为 1    

#define _Py_Dealloc(op) (                               \
    _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA          \
    (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
//引用计数为 0 时执行析构函数
//Py_TYPE(op)->tp_dealloc获取析构函数对应的函数指针
//再通过 * 获取指向的函数,函数接收 PyObject *
//所以将op转成PyObject *进行调用,最终回收对象


//增加引用计数
#define Py_INCREF(op) (                         \
    _Py_INC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
    ((PyObject *)(op))->ob_refcnt++) 
    //引用计数自增 1


//减少引用计数
#define Py_DECREF(op)                                   \
    do {                                                \
        PyObject *_py_decref_tmp = (PyObject *)(op);    \
        if (_Py_DEC_REFTOTAL  _Py_REF_DEBUG_COMMA       \
        --(_py_decref_tmp)->ob_refcnt != 0)             \
            _Py_CHECK_REFCNT(_py_decref_tmp)            \
        else                                             \
            _Py_Dealloc(_py_decref_tmp);                \
            //引用计数减1,如果减完1变成了0,则执行析构函数 
    } while (0)											\
        
//注意:Py_INCREF和Py_DECREF不可以处理NULL指针,会报错
//所以又有两个宏,做了一层检测,会判断对象指针为NULL的情况
#define Py_XINCREF(op)                                \
    do {                                              \
        PyObject *_py_xincref_tmp = (PyObject *)(op); \
        if (_py_xincref_tmp != NULL)                  \
            Py_INCREF(_py_xincref_tmp);               \
    } while (0)

#define Py_XDECREF(op)                                \
    do {                                              \
        PyObject *_py_xdecref_tmp = (PyObject *)(op); \
        if (_py_xdecref_tmp != NULL)                  \
            Py_DECREF(_py_xdecref_tmp);               \
    } while (0)
//当然减少引用计数,除了Py_DECREF和Py_XDECREF之外
//还有一个Py_CLEAR,也可以处理空指针的情况

因此这几个宏的作用如下:

  • _Py_NewReference:接收一个对象,将其引用计数设置为1,用于新创建的对象。此外我们在定义里面还看到了一个宏Py_REFCNT,这是用来获取对象引用计数的,也就是获取 ob_refcnt 成员的值。当然除了Py_REFCNT之外,我们之前还见到了一个宏叫Py_TYPE,这是专门获取对象的类型的,得到的是一个指向 PyTypeObject 结构体实例的指针,也就是 ob_type 成员的值
  • _Py_Dealloc:接收一个对象, 执行该对象的类型对象里面的析构函数, 来对该对象进行回收
  • Py_INCREF:接收一个对象, 将该对象引用计数自增1,即ob_refcnt++
  • Py_DECREF:接收一个对象, 将该对象引用计数自减1,即ob_refcnt–,如果自减之后发现为0,那么调用**_Py_Dealloc**
  • Py_XINCREF:和Py_INCREF功能一致,但是可以处理空指针
  • Py_XDECREF:和Py_DECREF功能一致,但是可以处理空指针
  • Py_CLEAR:和Py_XDECREF类似,也可以处理空指针

在一个对象的引用计数为 0 时,与该对象对应的析构函数就会被调用,但是要特别注意的是,我们刚才一直说调用析构函数之后会回收对象或者销毁对象、删除对象等等,意思是将这个对象从内存中抹去,但是这并不意味着最终一定调用 free 释放空间。换句话说就是对象没了,但是对象占用的内存却有可能还在。

如果对象没了,占用的内存也要释放的话,那么频繁申请、释放内存空间会使Python的执行效率大打折扣,更何况Python已经背负了人们对其执行效率的不满这么多年。

所以Python底层大量采用了缓存池的技术,使用这种技术可以避免频繁地申请和释放内存空间。因此在析构的时候,只是将对象占用的空间归还到缓存池中,并没有真的释放。

这一点,在后面剖析内置实例对象(PyFloatObject,PyListObject等等)的实现中,将会看得一清二楚,因为大部分内置的实例对象都会有自己的缓存池。

对象的分类

这里再补充一下对象的分类,我们之前根据支持的操作,将Python对象分成了数值型、序列型、映射型,总共3类,但其实我们是可以分为5类的:

  • Fundamental对象:类型对象,如int、float、bool、tuple
  • Numeric对象:数值对象,如int实例、float实例、bool实例
  • Sequence对象:序列对象,如str实例、list实例、tuple实例
  • Mapping对象:关联对象(映射对象),如dict实例
  • Internal对象:虚拟机在运行时内部使用的对象,如function实例(函数)、code实例(字节码)、frame实例(栈帧)、module实例(模块)、method实例(方法)。没错,函数、字节码、栈帧、模块、方法等等它们在底层也都是一个类的实例对象。比如:函数的类型是**<class ‘function’>,在底层对应PyFunctionObject。那么问题来了,<class ‘function’>的类型对象是什么呢?显然就是<class ‘type’>**啦。

小结

到这一章我们已经把所有的基础概念讲完了,从下一篇开始我们就要详细剖析内置对象的底层实现了,不如浮点数、比如浮点数、整数、字符串、元组、列表等等都是如何实现的。

有了目前为止的这些基础,我们后面就会轻松很多,先把对象、变量等概念梳理清楚,然后再来搞这些数据结构的底层实现。

Python垃圾回收机制:引用计数详解 然而,引用计数机制无法处理循环引用的情况,对于这种情况,Python引入了其他的垃圾回收机制。引用计数机制是一种高效的垃圾回收技术,因为它可以立即回收不再使用的对象,避免内存泄漏的发生。需要注意的是,引用计数机制无法处理循环引用的情况,即两个或多个对象相互引用,但没有其他外部引用指向它们。延迟垃圾回收通过延迟实际的垃圾回收操作,将多个引用计数更新操作合并为一个操作,以减少计数更新的次数。Python的垃圾回收机制基于引用计数的原理,本文将详细介绍Python垃圾回收机制中的引用计数。,引用计数增加到2。 阅读详情

相关推荐

5、Python编程:从源码编码到内置类型的全面解析

本文全面解析了Python编程中的源码编码和内置数据类型。从源码编码的基本概念到对象的身份、类型和引用机制,深入探讨了Python的核心数据结构,包括数字、字符串、列表、元组、字典和集合。此外,还详细介绍了类型选择的建议、性能优化以及常见错误的规避方法,帮助读者编写更加高效、简洁的Python代码。

leaf8的博客 54

Python笔记,内存管理(1)---引用计数

引用计数 在python中,每个对象都有存有该对象的引用总数,即引用计数(feference count) 引用计数原理 1.每个对象维护一个ob_ref减1,用来记录该对象当前被引用的次数 2.每当新的引用指向该对象时,它的引用计数ob_ref加1 3.每当该对象的引用失效时ob_ref减1 4.一旦对象的引用计数为0,该对象可以被回收,对象占用的内存空间将被释放 5.它的缺点是需要额外的空间维护计数,这个问题是其次的 6.最主要的问题是它不能解决对象的“循环引用” 获取引用计数.getrefcount(

weixin_49750432的博客 2253

深入解读Python源码:核心机制与优化技巧

Python的解释器架构主要包含三个组件:编译器、字节码执行引擎以及底层的内存管理机制。编译器将源代码转换为字节码,而字节码执行引擎则逐条解释执行这些字节码。Python解释器有多种实现,其中最著名的是CPython,它是用C语言编写的,并作为Python的官方标准解释器。它包括一个优化的虚拟机,负责执行字节码。

weixin_33068055的博客 742

11、python——内存管理(引用计数、垃圾回收、内存池机制、深度解析深浅拷贝(一看就会,不会你来揍我))

1、Python引用机制 • 对象是储存在内存中的实体。 • 我们在程序中写的对象名,只是指向这一对象的引用(reference) • 引用和对象分离,是动态类型的核心 • 引用可以随时指向一个新的对象(内存地址会不一样) 2、引用计数 当"a=500"时,引用计数就为+1;若是修改之后"a=600",原来的那片空间的引用计数就会-1;若是对象的引用计数为0时,销毁对象,这样就进行了回收。 ...

m0_48638643的博客 2846

小米路由器R1D进阶玩法:MIXBOX工具箱安装与插件管理指南

本文详细介绍了为小米路由器R1D安装MIXBOX工具箱的完整指南。通过开启SSH、执行一键安装脚本,用户可以轻松解锁路由器的进阶功能,如安装离线下载、内网穿透等插件,从而将旧设备转变为强大的家庭网络服务中心。

weixin_29292431的博客 1112

不同比例尺地质数据共享

包含20w、25w、100w、250w比例尺地质数据共享。

sinat_38828898的博客 2308

Python多线程机制

今天要跟大家一起来学习一下Python的多线程机制。有两个原因,其一是自己在学习中经常会使用到多线程,其二当然是自己对Python中的多线程并不是很了解。那么,今天和大家一起了解下~ Python多线程机制 开发多线程的应用系统,是在日常开发中经常会遇到的需求。同时,Python也为多线程系统的开发提供了很好的支持。大家应该都知道,Python多线程机制是在GIL(Global Interp...

weixin_30861797的博客 503

华为EC6108V9E刷机实战:从U盘准备到开机优化的完整避坑指南

本文提供华为悦盒EC6108V9E刷机与优化的完整实战指南。针对搭载RK3228芯片和安卓4.4.4系统的设备,从型号确认、固件选择、U盘准备,到详细刷机步骤、常见故障排除,以及刷机后的深度性能优化,手把手帮助用户规避风险,让旧盒子焕发新生,成为流畅的全能媒体中心。

weixin_29324401的博客 1191

python调用c/c++

一,封装若干函数到动态链接库: 1,mylib.h: int addone(int a); 2,mylib.c(*这里文件后缀只能是.c): /*mylib.c: >gcc -fpic -shared -o mylib.so \ -I/usr/include/python2.7 \ mylib.c wrap_mylib.c*/ int addone(int a...

liuzq的专栏 303

保姆级拆解:HP 1312NF/CM1415打印机进纸离合器清洁与更换全记录(附B站/油管视频指路)

本文详细记录了HP 1312NF打印机进纸离合器故障的诊断与修复全过程,包括故障判断、工具准备、拆解步骤、清洁更换技巧及预防措施。特别针对离合器内部海绵老化粘连问题,提供了电工胶布和硬纸片两种实用替代方案,并附有B站/油管视频指路,帮助用户轻松完成打印机维修。

weixin_31102231的博客 374

【WRF-Chem工具】anthro_emiss 详解:生成人为排放数据

anthro_emiss 详解:生成人为排放数据

WW、forever的博客 2054

关于 Python 垃圾回收

0.引言1.引用计数器1.1.环状双向链表 refchain1.2.类型封装结构体1.3.引用计数器1.4.循环引用问题2.标记清除3.分代回收4.小结5. 缓存机制5.1.池(int、字符串)5.2.free_list(float/list/tuple/dict) 引用计数器 标记清除 分代回收 缓存机制 0.引言 最近一直对于python的垃圾回收机制有些疑惑,于是查了一些资料,看了一些大神的解析,总结了一下,供自己以后参考,避免忘记。 在b站学习了一下,这位

coole_true的博客 640

锂电池剩余使用寿命预测(RUL) | 基于Stacked-LSTM-Autoencoder的锂电池寿命多变量多步预测(Tensorflow)

锂电池剩余使用寿命预测(RUL) | 基于Stacked-LSTM-Autoencoder的锂电池寿命多变量多步预测(Tensorflow)

前程算法屋的博客 851

Python源码解读之二 万物皆对象(下)

初探PyObject 首先我们再次来回顾一下,在上一篇提到过,“类”和“对象”这两个概念在Python中都是用对象实现的。“类"是一种对象,称为"类型对象”,“类"实例化得到的也是"对象”,称为"实例对象"。 实现对象机制的基石–PyObject Python中的任何对象在C中都对应一个结构体实例,在Python中创建一个对象,等价于在C中创建一个结构体实例。所以Python中的对象本质上就是C中malloc函数为结构体实例在堆区申请的一块内存。 /* Nothing is actually declare

java_0429的博客 440

工程师必读一次性讲明白系列(十三)眼图、阻抗匹配、信号一致性、射频匹配、电磁感应

概念主要作用影响因素解决方法眼图评估信号质量,显示失真和噪声噪声、信号失真、时序抖动改善信号源、使用低噪声组件阻抗匹配避免信号反射,提高传输效率阻抗不匹配、传输线路特性使用匹配电路、适配器信号一致性保证信号稳定准确传输传输线路、噪声干扰使用屏蔽、滤波器,选择合适线路射频匹配确保射频信号高效传输天线设计、阻抗不匹配使用射频匹配器、调整天线设计电磁感应防止电磁干扰对信号的影响设备之间的电磁干扰(EMI)屏蔽、接地、滤波器。

weixin_43199439的博客 157

YOLOv8【第十章:多任务扩展深度篇·第18节】不规则工业缺陷分割——针对划痕、裂纹的 Seg 模型调优!

🏆 本文收录于 《YOLOv8实战:从入门到深度优化》 专栏。该专栏系统复现并梳理全网各类 YOLOv8 改进与实战案例(当前已覆盖分类 / 检测 / 分割 / 追踪 / 关键点 / OBB 检测等方向),坚持持续更新 + 深度解析,质量分长期稳定在 97 分以上,可视为当前市面上 覆盖较全、更新较快、实战导向极强 的 YOLO 改进系列内容之一。

**My Coding Family** 3980

花了4000块钱报班,面试时被问到Python的垃圾回收机制,答不上来被PASS了(1)

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。一个人可以走的很快,但一群人才能走的更远。

m0_61549953的博客 739

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Python垃圾回收机制

Python的垃圾回收机制到底是什么回事?从网上找到一大堆的文档,看的也是一知半解,最终就学会了一句话:引用计数器为主、分代码回收和标记清除为辅。 就这么一知半解的去忽悠面试官了,面试官如果恰好也只会这几句话,那便达成和解了。 本篇文章从C语言源码底层来聊聊Python内存管理和垃圾回收机制到底是个啥?让你能够真正了解内存管理&垃圾回收。 1. 白话垃圾回收 用通俗的语言解释内存管理和垃圾回收的过程,搞懂这一部分就可以去面试、去装逼了… 1.1 大管家refchain 在Python的C

qq_32630565的博客 379

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

ok-ww 完整指南:鸣潮后台自动刷声骸与一键日常快速上手

ok-ww 是一个开源的鸣潮(Wuthering Waves)自动化程序:用图像识别看懂画面,通过 Windows 系统接口模拟键鼠操作,把刷声骸、打世界 Boss、清日常这些重复劳动放到后台执行,你只管验收结果。 ## 原理与边界:它怎么工作,又明确不做什么 一句话:**程序用眼睛看画面、用手点键鼠**。 - **看画面**:靠图像识别判断场上角色、技能是否转好、是不是 Boss、副本进没

gitblog_00737的博客 433

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

python中的垃圾回收机制_python里面的垃圾回收机制

文章链接:https://www.jianshu.com/p/1e375fb40506Garbage collection(GC)现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自...

weixin_39979167的博客 85

Python 源码解读:核心数据结构与算法实现分析

本文深入剖析Python核心数据结构与算法实现原理,从源码层面解析装饰器、垃圾回收等关键机制。文章提供源码阅读指南,指出关键入口文件位置,并总结面试考察要点。进阶部分涵盖错误处理、性能监控、测试策略等最佳实践,给出生产部署清单和常见问题排查方法。通过分析内存泄漏和性能瓶颈案例,帮助开发者从"会用"升级到"精通",掌握Python底层实现原理与高效开发技巧。

斌味代码的博客 497

python 垃圾回收机制

python 垃圾回收机制

jntmjntm的博客 217

Python源码学习笔记:Python对象的底层实现

在“Python源码学习笔记:Python万物皆对象”中,我们对Python的对象类型体系有了一定的认识,这篇博客将从源码层面来介绍Python中万物皆对象的底层实现。

xiaoli_Jenny的博客 991

一本书掌握自动内存回收的机制《垃圾回收的算法与实现》(好书分享更新中)

垃圾回收的算法与实现分为“算法篇”和“实现篇”两大部分。算法篇介绍了标记-清除算法、引用计数法、复制算法、标记-压缩算法、保守式GC、分代垃圾回收、增量式垃圾回收、RCImmix算法等几种重要的算法;实现篇介绍了垃圾回收在Python、DalvikVM、Rubinius、V8等几种语言处理程序中的具体实现。 本书特色 ★ Ruby之父松本行弘推荐:上古传承之魔法,彻底揭开垃圾回收的秘密! ★ 日本天才程序员兼LISP黑客竹内郁雄审校 ★ 254幅图解,轻松掌握GC经典算法 ★ 实际源码剖析,深入探讨GC具

qq_18591859的博客 309

Python运行时底层原理:CPython对象模型与内存管理解析

Python作为解释型语言,其执行效率与稳定性高度依赖CPython解释器的底层机制。理解对象模型——即一切皆对象、引用计数、id/is/==语义差异——是规避内存泄漏、误用缓存和类型比较错误的前提;掌握内存管理——包括引用计数、循环垃圾回收及list.clear()不释放缓冲区等细节——直接决定数据密集型服务的长期健壮性。这些原理支撑着GIL行为、字节码优化(如INPLACE_ADD vs BINARY_ADD)及真实场景中的性能调优。本文聚焦CPython核心支柱,结合objgraph、dis、trac

weixin_30414305的博客 401
上一篇: Python源码解读之三 对象的创建
下一篇: Python源码解读之五 对象的多态性和行为
jilingwei_123
博客等级 码龄11年 6粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值