hzk20220818

Python内存管理-引用计数-垃圾回收机制(通俗易懂)

Python内存管理-垃圾回收机制

1. Python引用计数

首先,什么是引用计数
说到引用计数,就得先了解什么是python对象

1.1 python对象

python中一切皆对象(数字、字符串、元组、列表、字典、函数、方法、类、模块),Python的万物皆对象从感性上可以解释为:Python 中的一切都可以赋值给变量或者作为参数传递给函数。

1.1.1 Python的所有对象都有三个特性:

(1)函数 id() ,每个对象都有一个唯一的身份标识,即该对象的内存地址
(2)函数 type() 来查看对象的类型,对象的类型决定了对象可以保有哪些属性和方法,可以进行哪些操作,遵循怎样的规则
(3)函数 sys.getrefcount()方法查看对象的引用计数

当使用sys.getrefcount查看-5到256之内的数字对象时,会发现引用计数非常大,这是因为python自己创建了-5到256内的所有数字对象,且引用很多,不用用户再创建,具体详情可搜索 小数据池 。

(4)函数 del 对象,可以删除内存中对象

引用计数:
对象都包含了两个头部信息,一个是类型标志符,标识这个对象的类型;另一个是引用计数器,记录当前指向该对象的引用数目,表示这个对象被多少个变量名所引用。

a=1000

a是变量名,1000是创建在内存中的实际对象,“=”将1000在内存中的地址给a变量值(python中赋值,参数传递 都是原对象地址的传递),1000的引用计数+1

2. Python垃圾回收(简单基础版)

在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数器(ob_refcnt)。程序在运行的过程中会实时的更新ob_refcnt的值,来反映引用当前对象的名称数量。当某对象的引用计数值为0,那么它的内存就会被立即释放掉。当然循环引用也会被释放。

2.1引用计数变化的情况

以下情况是导致引用计数加一的情况:

对象被创建,例如a=2
对象被引用,b=a
对象被作为参数,传入到一个函数中
对象作为一个元素,存储在容器中

下面的情况则会导致引用计数减一:

对象别名被显示销毁 del
对象别名被赋予新的对象
一个对象离开他的作用域
对象所在的容器被销毁或者是从容器中删除对象

3.何时python会自动启动垃圾回收?

垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。如果内存中的对象不多,就没有必要总启动垃圾回收。所以,Python只会在特定条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动扫描。

gc模块的get_threshold()方法,查看该阈值

4.手动启动垃圾回收机制

使用gc.collect()

5.扫描策略--分代回收

垃圾回收是先扫描再回收,但扫描时并不是使用对象都一视同仁一起扫描。

Python将所有的对象分为0,1,2三代。所有的新建对象都是0代对象。当某一代对象经历过垃圾回收,依然存活,那么它会归入1代对象。垃圾回收启动时,一定会扫描所有的0代对象。如果0代经过一定次数垃圾回收,那么就启动对0代和1代的扫描清理。当1代也经历了一定次数的垃圾回收后,那么会启动对0,1,2,即对所有对象进行扫描。

get_threshold()

返回(700, 10, 10)元组,其中两个10。第一个10表示,每10次0代垃圾回收,会配合1次1代的垃圾回收;第二个10表示:而每10次1代的垃圾回收,才会有1次的2代垃圾回收。

同样可以用set_threshold()来调整,比如对2代对象进行更频繁的扫描。

import gc
gc.set_threshold(700, 10, 5)

posted on 2022-08-19 09:41  hzk-shzdx-university  阅读(217)  评论(0编辑  收藏  举报

导航