欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > python >内容正文

python

python垃圾回收 采用方式_python-面向对象-10-__del__析构方法/垃圾回收机制

发布时间:2024/7/23 python 36 豆豆
生活随笔 收集整理的这篇文章主要介绍了 python垃圾回收 采用方式_python-面向对象-10-__del__析构方法/垃圾回收机制 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

Python语言自带垃圾回收机制,为了能够比较清楚说明白Python的垃圾回收机制的原理,我们今天就从最底层的解释器开始,采用由内到外的方式来说明。

1.Python默认解释器CPython

Python语言拥有多种解释器,但是默认采用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 引用计数入门示例

import sys

a1 = [1, 2, 3]

print(sys.getrefcount(a1))

运行结果:

2

程序运行说明:

首先第一次赋值操作,很容易理解变量a1指向的对象[1,2,3]的引用次数为1,然后在调用sys.getrefcount(a1)的时候,会把形参认为是一个局部变量a1,不是全局变量a1,但是对应的值是一样的,所以这个时候会增加一个引用次数,变成2。

2.3 赋值增加引用计数

import sys

a1 = [1, 2, 3]

print(id(a1))

print(sys.getrefcount(a1))

a2 = a1

print(sys.getrefcount(a1))

print(sys.getrefcount(a1))

print("--" * 20)

a3 = [1, 2, 3]

print(id(a3))

print(sys.getrefcount(a3))

运行结果:

4726471808

2

3

3

----------------------------------------

4726471888

2

程序说明: 第一部分和上面的例子是一样的,但是增加一个id(a1)的方法,会打印出a1的内存地址。当执行a2 = a1的时候,增加了一个引用。sys.getrefcount(a1)是同一个,所以两次执行也不会增加引用。虽然a1和a3对应的值是相同的,但是id值不一样,相当是一个新的,所以计算计算引用从1开始计算,增加sys.getrefcount(a1)里面的一个,最后结果为2。

2.4 对象包含在其他数据结构中会增加引用次数

import sys

a1 = [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))

运行结果:

2

3

4

5

程序运行说明: 这部分是可以正常理解的。

但是当数据变化的时候,下面的例子,我找了资料也没有具体说清楚:

import sys

a1 = 1

print(sys.getrefcount(a1))

a2 = [a1]

print(sys.getrefcount(a1))

a3 = (a1, )

print(sys.getrefcount(a1))

a4 = {"key1": a1}

print(sys.getrefcount(a1))

运行结果:

4378

4379

4380

4381

程序说明: 这部分的原因是由于Python中对象缓存造成的,对于一些数值较小的对象,会经常使用到,对这一部分对象存在内部的缓存机制。也就是会存在多个引用,具体多少数值,和运行平台、解释器、数值取值大小都有都有印象。 下面通过两段简单代码来说明: 第一段: Python命令行执行

>>> a1=1

>>> id(a1)

140732194454592

>>> a2=1

>>> id(a2)

140732194454592

>>>

>>> b1=257

>>> id(b1)

1878299222992

>>> b2=257

>>> id(b2)

1878301364976

第二段: Pycharm中保存文件执行

a1 = 1

a2 = 1

print(id(a1))

print(id(a2))

b1 = 257

b2 = 257

print(id(b1))

print(id(b2))

b1 = 99999999999999999999999999999999999999999999999

b2 = 99999999999999999999999999999999999999999999999

print(id(b1))

print(id(b2))

运行结果:

140732194454592

140732194454592

2195360849840

2195360849840

2195386463936

2195386463936

通过两组程序我们发现,虽然Python存在对象的缓存机制,但是对于不同的运行环境中,存在一定的差异。在命令行中,以整数为例:[-5, 256]这个区间的范围会被缓存,但是在文件中,无论多大数值都会被缓存。

3.析构方法

3.1 析构方法说明

__del__方法称为"析构方法",用于实现对象被销毁时所需要的操作。比如:释放对象占用的资源。使用场景:

打开的文件资源

网络连接

数据库操作

。。。

Python实现自动的垃圾回收,当对象没有被引用时(引用计数为0),由垃圾回收器调用__del__方法。

我们也可以使用del语句手动删除对象,从而保证调用__del__方法。

系统会自动提供__del__方法,一般不需要自定义析构方法。

3.2 代码示例

代码:

class Person:

def __init__(self, name):

self.name = name

def __del__(self):

print("销毁对象:{0}".format(self.name))

p1 = Person("p1")

p2 = Person("p2")

# 使用del方法主动销毁对象p2

del p2

print("程序结束")

运行结果:

销毁对象:p2

程序结束

销毁对象:p1

代码说明:

因为手动调用del方法注销p2对象,本质上还是调用对象p2本身的注销机制,在注销之前会调用自身的__del__()方法,所以第一行输出销毁对象:p2.

程序代码运行结束,执行打印语句,所以第二行显示:程序结束

python的垃圾回收器,对程序进行处理,发现对象p1目前仍占用内存,没有被清除。启动垃圾回收机制,类似步骤一,所以第三行输出: 销毁对象:p1

备注:

更多精彩博客,请访问:聂发俊的技术博客

对应视频教程,请访问:python400

完整markdown笔记,请访问: python400_learn_github

总结

以上是生活随笔为你收集整理的python垃圾回收 采用方式_python-面向对象-10-__del__析构方法/垃圾回收机制的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。