当前位置: 首页 > 后端技术 > Python

python-object-oriented-10-__del__destruction方法-垃圾回收机制

时间:2023-03-26 13:29:12 Python

Python语言有自己的垃圾回收机制。为了能够清楚的解释Python的垃圾回收机制的原理,今天我们就从底层解释器说起。首先,用由内而外的方法来说明。1.Python默认解释器CPythonPython语言有多种解释器,但默认实现是CPython。CPython实际上是用C语言编写的。主要功能如下:将python代码编译成字节码(bytecode)并在虚拟机上运行编译好的python程序CPython是用C语言编写的,C语言本身不支持面向对象编程。正因为如此,CPython代码中有很多有趣的设计来实现这些原本不支持的功能。:比如PyObject。PyObject是Python中所有对象的鼻祖,它只包含两个东西:ob_refcnt:引用计数ob_type:指向另一种类型的指针ob_refcnt引用计数用于接下来要解释的垃圾回收。2.垃圾回收机制2.1垃圾回收简介Python中的垃圾回收机制是利用引用计数策略实现的。当一个对象的ob_refcnt大于0时,说明存在引用。这时,对象不会被垃圾回收。当一个对象的ob_refcnt引用数等于0时,表示该对象没有任何引用,说明它是一个空闲废弃对象,将进入垃圾回收阶段。Python允许您使用sys模块检查对象的当前引用计数。您可以使用sys.getrefcount(numbers),但请记住,将对象传递给getrefcount()会将引用计数递增1。这里有几段代码可以演示:2.2引用计数入门示例importsysa1=[1,2,3]print(sys.getrefcount(a1))运行结果:2程序运行说明:首先,第一次赋值操作很容易理解变量a1指向的对象[1,2,3]有一个引用计数为1,然后调用sys.getrefcount(a1)时,形参会被认为是局部变量a1,而不是全局变量a1,但是对应的值是一样的,所以此时,a引用计数将添加成为2。2.3赋值增加引用计数importsysa1=[1,2,3]print(id(a1))print(sys.getrefcount(a1))a2=a1print(sys.getrefcount(a1))print(sys.getrefcount(a1))print("--"*20)a3=[1,2,3]print(id(a3))print(sys.getrefcount(a3))运行结果:4726471808233--------------------------------------47264718882程序说明:第一部分同上例,只是增加一个id(a1)该方法会打印出a1的内存地址。当执行a2=a1时,添加了一个引用。sys.getrefcount(a1)是一样的,所以做两次不会增加引用。虽然a1和a3对应的值是一样的,但是id值是不一样的,挺新的,所以计算的计算参考从1开始,sys.getrefcount(a1)中的是添加,最终结果为2。2.4对象包含在其他数据结构中增加了引用数importsysa1=[1,2,3]print(sys.getrefcount(a1))a2=[a1]print(sys.getrefcount(a1))a3=(a1,)print(sys.getrefcount(a1))a4={"key1":a1}print(sys.getrefcount(a1))result:2345程序运行说明:这部分可以理解。但是当数据变化的时候,下面这个例子,我找了资料,没有解释清楚:importsysa1=1print(sys.getrefcount(a1))a2=[a1]print(sys.getrefcount(a1))a3=(a1,)print(sys.getrefcount(a1))a4={"key1":a1}print(sys.getrefcount(a1))result:4378437943804381??程序说明:这部分是Python中对象缓存引起的,对于一些值很小的对象,经常用到,这部分对象有内部缓存机制。也就是说会有多个引用,具体值有多少,对运行平台、解释器、值的值都有印象。下面用两段简单的代码来说明:第一段:Python命令行执行>>>a1=1>>>id(a1)140732194454592>>>a2=1>>>id(a2)140732194454592>>>>>>b1=257>>>id(b1)1878299222992>>>b2=257>>>id(b2)1878301364976第二段:在Pycharm中保存文件,执行a1=1a2=1print(id(a1))print(id(a2))?b1=257b2=257print(id(b1))print(id(b2))?b1=99999999999999999999999999999999999999999999999b2=99999999999999999999999999999999999999999999999print(id(b1))print(id(b2))运行结果:1407321944545921407321944545922195360849840219536084984021953864639362195386463936通过两套程序我们发现Python虽然有对象缓存机制,但是在不同的运行环境下还是有一定差异的在命令行中,以一个整数为例:[-5,256]范围内会被缓存,但在文件中,无论值多大,都会被缓存。3.销毁方法3.1销毁方法说明__del__方法称为“销毁方法”,用于实现对象销毁时所需的操作。例如:释放对象占用的资源。使用场景:打开文件资源网络连接数据库操作。..Python实现了自动垃圾收集。当对象未被引用时(引用计数为0),垃圾收集器调用__del__方法。我们也可以使用del语句手动删除对象,从而保证调用__del__方法。系统会自动提供__del__方法,一般不需要自定义析构方法。3.2代码示例代码:classPerson:def__init__(self,name):self.name=namedef__del__(self):print("Destroyobject:{0}".format(self.name))p1=Person("p1")p2=Person("p2")#使用del方法主动销毁对象p2delp2print("ProgramEnd")运行结果:destroyobject:p2programenddestroyobject:p1代码说明:p2对象被取消通过手动调用del方法,本质上是调用对象p2本身的注销机制。在注销之前,它会调用自己的__del__()方法,所以第一行输出被销毁的对象:p2。程序代码运行后,执行print语句,所以第二行显示:程序结束后,python垃圾回收器处理程序,发现对象p1仍然占用内存,没有被清除。启动垃圾回收机制,与步骤1类似,所以第三行输出:Destroyobject:p1备注:更多精彩博客请访问:聂法军的技术博客对应视频教程请访问:python400完整markdown笔记请访问访问:python400_learn_github