当前位置:首页 » 编程语言 » python的对象引用计数

python的对象引用计数

发布时间: 2023-06-03 14:16:21

python面试题总结1-内存管理机制

(1).引用计数
(2). 垃圾回收
(3). 内存池机制

在python中每创建一个对象,对应的会有一个引用计数,当发生赋值操作如a=b,对应的b的引用计数会自动加1,当引用的对象被清除或者函数结束时,引用计数会自动减1。

在python中使用引用计数,标记清楚,分代回收三种方式进行垃圾回收。
其中,引用计数当对象的引用计数归0时,对象会自动被清除。标记清除机制是首先遍历所有对象,如果对象可达,就说明有变量引用它,则标记其为可达的。如果不可达,则对其进行清除。分代回收是当对象创建时被标记为第0代,经过一次垃圾回收之后,余下的对象被标记为第1代,最高为第2代。其原理是,对象的生存期越长,月可能不是垃越。

ython语言虽然提供了对内存的垃圾收集机制,但实际上它将不用的内存放到内存池而不是返回给操作系统,所以就有了以下:

1 Pymalloc机制;这个主要是为了加速Python的执行效率,Python引入了一个内存池机制,用于管理,为了对小块内存的申请和释放。

2 Python中所有小于256个字节的对象都是依靠pymalloc分配器来实现的,而稍大的对象用的则是系统的malloc。

3 对于Python对象,比如整数、浮点数和List这些,都有自己独立的内存池,对象间并不共享他们的内存池。换句话说就是,假设你分配并且释放了大量的整数,那么用于缓存这些整数的内存就不能再分配给浮点数。

❷ Python如何进行内存管理

Python是如何进行内存管理的?

答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制。

一、对象的引用计数机制

Python内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。

引用计数增加的情况:

1,一个对象分配一个新名称

2,将其放入一个容器中(如列表、元组或字典)

引用计数减少的情况:

1,使用del语句对对象别名显示的销毁

2,引用超出作用域或被重新赋值

Sys.getrefcount( )函数可以获得对象的当前引用计数

多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。

相关推荐:《Python视频教程》

二、垃圾回收

1,当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。

2,当两个对象a和b相互引用时,del语句可以减少a和b的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。

三、内存池机制

Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。

1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。

3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

❸ Python引入了一个机制:引用计数。

python内部使用引用计数,来保持追踪内存中的对象,
Python内部记录了对象有多少个引用
,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
总结一下对象会在一下情况下引用计数加1:
1.对象被创建:x=4
2.另外的别人被创建:y=x
3.被作为参数传递给函数:foo(x)
4.作为容器对象的一个元素:a=[1,x,'33']
引用计数减少情况
1.一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。
2.对象的别名被显式的销毁:del x ;或者del y
3.对象的一个别名被赋值给其他对象:x=789
4.对象从一个窗口对象中移除:myList.remove(x)
5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。垃圾回收
1、当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。
它会去检查那些引用计数为0的对象
,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。
2、垃圾回收机制还有一个
循环垃圾回收器
, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。
在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。
这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的
malloc。另外Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响
Python的执行效率。这也就是之前提到的

❹ python的内存管理机制

论坛

活动

招聘

专题

打开CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved

登录

XCCS_澍
关注
Python 的内存管理机制及调优手段? 原创
2018-08-05 06:50:53

XCCS_澍

码龄7年

关注
内存管理机制:引用计数、垃圾回收、内存池。
一、引用计数:
    引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。
二、垃圾回收 :
1. 引用计数
      引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
2. 标记清除
     如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
3. 分代回收
     从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。

❺ python程序执行完有对象的引用计数不为0,会怎么处理

1. 整个执行结束后,解释器退出时会清理所有解释器产生的对象。2. CPython的实现里有个mark-sweep。因此即使出现了循环引用又被扔掉的对象,最终还是会被回收的。3. 你的例子不构成循环引用,完全会根据计数正常回收。清理b时,b所指list引用归0,list被回收,list中对a的引用就会减1,因此没有任何问题。

❻ Python 的内存管理机制

Python采用自动内存管理,即Python会自动进行垃圾回收,不需要像C、C++语言一样需要程序员手动释放内存,手动释放可以做到实时性,但是存在内存泄露、空指针等风险。

Python自动垃圾回收也有自己的优点和缺点:优点:

缺点:

Python的垃圾回收机制采用 以引用计数法为主,分代回收为辅 的策略。

先聊引用计数法,Python中每个对象都有一个核心的结构体,如下

一个对象被创建时,引用计数值为1,当一个变量引用一个对象时,该对象的引用计数ob_refcnt就加一,当一个变量不再引用一个对象时,该对象的引用计数ob_refcnt就减一,Python判断是否回收一个对象,会将该对象的引用计数值ob_refcnt减一判断结果是否等于0,如果等于0就回收,如果不等于0就不回收,如下:

一个对象在以下三种情况下引用计数会增加:

一个对象在以下三种情况引用计数会减少:

验证案例:

运行结果:

事实上,关于垃圾回收的测试,最好在终端环境下测试,比如整数257,它在PyCharm中用下面的测试代码打印出来的结果是4,而如果在终端环境下打印出来的结果是2。这是因为终端代表的是原始的Python环境,而PyCharm等IDE做了一些特殊处理,在Python原始环境中,整数缓存的范围是在 [-5, 256] 的双闭合区间内,而PyCharm做了特殊处理之后,PyCharm整数缓存的范围变成了 [-5, 无穷大],但我们必须以终端的测试结果为主,因为它代表的是原始的Python环境,并且代码最终也都是要发布到终端运行的。

好,那么回到终端,我们来看两种特殊情况

前面学习过了,整数缓存的范围是在 [-5, 256] 之间,这些整数对象在程序加载完全就已经驻留在内存之中,并且直到程序结束退出才会释放占有的内存,测试案例如下:

如果字符串的内容只由字母、数字、下划线构成,那么它只会创建一个对象驻留在内存中,否则,每创建一次都是一个新的对象。

引用计数法有缺陷,它无法解决循环引用问题,即A对象引用了B对象,B对象又引用了A对象,这种情况下,A、B两个对象都无法通过引用计数法来进行回收,有一种解决方法是程序运行结束退出时进行回收,代码如下:

前面讲过,Python垃圾回收机制的策略是 以引用计数法为主,以分代回收为辅 。分代回收就是为了解决循环引用问题的。

Python采用分代来管理对象的生命周期:第0代、第1代、第2代,当一个对象被创建时,会被分配到第一代,默认情况下,当第0代的对象达到700个时,就会对处于第0代的对象进行检测和回收,将存在循环引用的对象释放内存,经过垃圾回收后,第0代中存活的对象会被分配为第1代,同样,当第1代的对象个数达到10个时,也会对第1代的对象进行检测和回收,将存在循环引用的对象释放内存,经过垃圾回收后,第1代中存活的对象会被分配为第2代,同样,当第二代的对象个数达到10个时,也会对第2代的对象进行检测和回收,将存在循环引用的对象释放内存。Python就是通过这样一种策略来解决对象之间的循环引用问题的。

测试案例:

运行结果:

如上面的运行结果,当第一代中对象的个数达到699个即将突破临界值700时(在打印699之前就已经回收了,所以看不到698和699)进行了垃圾回收,回收掉了循环引用的对象。

第一代、第二代、第三代分代回收都是有临界值的,这个临界值可以通过调用 gc.get_threshold 方法查看,如下:

当然,如果对默认临界值不满意,也可以调用 gc.set_threshold 方法来自定义临界值,如下:

最后,简单列出两个gc的其它方法,了解一下,但禁止在程序代码中使用

以上就是对Python垃圾回收的简单介绍,当然,深入研究肯定不止这些内容,目前,了解到这个程度也足够了。

❼ Python对象

众所周知,Python是一门面向对象的语言,在Python无论是数值、字符串、函数亦或是类型、类,都是对象。
对象是在 堆 上分配的结构,我们定义的所有变量、函数等,都存储于堆内存,而变量名、函数名则是一个存储于 栈 中、指向堆中具体结构的引用。

要想深入学习Python,首先需要知道Python对象的定义。

我们通常说的Python都是指CPython,底层由C语言实现,源码地址: cpython [GitHub]
Python对象的定义位于 Include/object.h ,是一个名为 PyObject 的结构体:

Python中的所有对象都继承自PyObejct,PyObject包含一个用于垃圾回收的双向链表,一个引用计数变量 ob_refcnt 和 一个类型对象指针 ob_type

从PyObejct的注释中,我们可以看到这样一句:每个指向 可变大小Python对象 的指针也可以转换为 PyVarObject* (可变大小的Python对象会在下文中解释)。 PyVarObejct 就是在PyObject的基础上多了一个 ob_size 字段,用于存储元素个数:

在PyObject结构中,还有一个类型对象指针 ob_type ,用于表示Python对象是什么类型,定义Python对象类型的是一个 PyTypeObject 接口体

实际定义是位于 Include/cpython/object.h 的 _typeobject :

在这个类型对象中,不仅包含了对象的类型,还包含了如分配内存大小、对象标准操作等信息,主要分为:

以Python中的 int类型 为例,int类型对象的定义如下:

从PyObject的定义中我们知道,每个对象的 ob_type 都要指向一个具体的类型对象,比如一个数值型对象 100 ,它的ob_type会指向 int类型对象PyLong_Type 。

PyTypeObject结构体第一行是一个PyObject_VAR_HEAD宏,查看宏定义可知PyTypeObject是一个变长对象

也就是说,归根结底 类型对象也是一个对象 ,也有ob_type属性,那 PyLong_Type 的 ob_type 是什么呢?
回到PyLong_Type的定义,第一行 PyVarObject_HEAD_INIT(&PyType_Type, 0) ,查看对应的宏定义

由以上关系可以知道, PyVarObject_HEAD_INIT(&PyType_Type, 0) = { { _PyObject_EXTRA_INIT 1, &PyType_Type } 0} ,将其代入 PyObject_VAR_HEAD ,得到一个变长对象:

这样看就很明确了,PyLong_Type的类型就是PyType_Typ,同理可知, Python类型对象的类型就是PyType_Type ,而 PyType_Type对象的类型是它本身

从上述内容中,我们知道了对象和对象类型的定义,那么根据定义,对象可以有以下两种分类

Python对象定义有 PyObject 和 PyVarObject ,因此,根据对象大小是否可变的区别,Python对象可以划分为 可变对象(变长对象) 和 不可变对象(定长对象)

原本的对象a大小并没有改变,只是s引用的对象改变了。这里的对象a、对象b就是定长对象

可以看到,变量l仍然指向对象a,只是对象a的内容发生了改变,数据量变大了。这里的对象a就是变长对象

由于存在以上特性,所以使用这两种对象还会带来一种区别:
声明 s2 = s ,修改s的值: s = 'new string' ,s2的值不会一起改变,因为只是s指向了一个新的对象,s2指向的旧对象的值并没有发生改变
声明 l2 = l ,修改l的值: l.append(6) ,此时l2的值会一起改变,因为l和l2指向的是同一个对象,而该对象的内容被l修改了

此外,对于 字符串 对象,Python还有一套内存复用机制,如果两个字符串变量值相同,那它们将共用同一个对象:

对于 数值型 对象,Python会默认创建0~2 8 以内的整数对象,也就是 0 ~ 256 之间的数值对象是共用的:

按照Python数据类型,对象可分为以下几类:

Python创建对象有两种方式,泛型API和和类型相关的API

这类API通常以 PyObject_xxx 的形式命名,可以应用在任意Python对象上,如:

使用 PyObjecg_New 创建一个数值型对象:

这类API通常只能作用于一种类型的对象上,如:

使用 PyLong_FromLong 创建一个数值型对象:

在我们使用Python声明变量的时候,并不需要为变量指派类型,在给变量赋值的时候,可以赋值任意类型数据,如:

从Python对象的定义我们已经可以知晓造成这个特点的原因了,Python创建对象时,会分配内存进行初始化,然后Python内部通过 PyObject* 变量来维护这个对象,所以在Python内部各函数直接传递的都是一种泛型指针 PyObject* ,这个指针所指向的对象类型是不固定的,只能通过所指对象的 ob_type 属性动态进行判断,而Python正是通过 ob_type 实现了多态机制

Python在管理维护对象时,通过引用计数来判断内存中的对象是否需要被销毁,Python中所有事物都是对象,所有对象都有引用计数 ob_refcnt 。
当一个对象的引用计数减少到0之后,Python将会释放该对象所占用的内存和系统资源。
但这并不意味着最终一定会释放内存空间,因为频繁申请释放内存会大大降低Python的执行效率,因此Python中采用了内存对象池的技术,是的对象释放的空间会还给内存池,而不是直接释放,后续需要申请空间时,优先从内存对象池中获取。

热点内容
java培训有人要吗 发布:2024-05-09 03:21:16 浏览:969
c语言多次输入数据 发布:2024-05-09 03:12:50 浏览:737
pythonide使用 发布:2024-05-09 02:56:52 浏览:349
社区电商源码 发布:2024-05-09 02:33:00 浏览:149
辽事通登记需要的密码是什么 发布:2024-05-09 02:25:45 浏览:283
云服务器选择什么系统 发布:2024-05-09 01:55:51 浏览:968
mel脚本编程全攻略 发布:2024-05-09 01:54:43 浏览:479
如何在机房安装ntp服务器 发布:2024-05-09 01:13:57 浏览:206
ideajavaidea 发布:2024-05-09 01:02:14 浏览:965
oas存储 发布:2024-05-09 00:57:49 浏览:801