python循环引用
1. 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的执行效率。这也就是之前提到的
2. 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. 分代回收
从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。
3. Python怎么避免循环import
引用在csdn一没猜仔位大神的解决方法
解决循环import的方法主要有几种枯汪:
1.延迟导入
即把import语句写在方法或函数里面,将它的作用域限制在局部。这种方法的缺点就是会有性能问题。
2.将from xxx import yyy改成import xxx;xxx.yyy来访问的形式
3.组织代码
出现循环import的问题往往意味着代码的布局有问题。可以合并或者分离竞争资源。合并的话就是都写到一个文件里面去。分离的话就是把需要import的资源提取到一个第三方文件去。总之就是将循环变成单向。
希望我的回答可以兆唤帮到你:-)
4. 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垃圾回收的简单介绍,当然,深入研究肯定不止这些内容,目前,了解到这个程度也足够了。
5. python xml循环写入覆盖了怎么办
在输入一遍。
这种情况下,执行该package时会抛出error错误,即循环引用,因为molea试图去引入moleb时,而moleb首先要引入molea,这会导致Python解释器无法执行下去。
mole中的函数以attribute的方式引用anothermole中的函数或变量等,之所以要挂上packagename来引入,是由于import这种形式的相对引入会报语法错误,而挂上package的绝对引入,Python2和3都支持。