当前位置:首页 » 编程语言 » python回收

python回收

发布时间: 2022-04-14 19:39:07

⑴ 如何理解和掌握python垃圾回收机制

现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。
对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配回收内存的问题。

⑵ 请问各位大佬用python怎么读取回收站然后删除所有回收站里的文件

您好,对于你的遇到的问题,我很高兴能为你提供帮助,我之前也遇到过哟,以下是我的个人看法,希望能帮助到你,若有错误,还望见谅!。os包的rmdir()函数可以用来删除一个文件夹,但是文件夹必须是空的。一种可行的方法是读取文件夹的文件列表,逐个删除文件夹中的所有文件,然而文件夹中可能还有文件夹,因此这是一个递归的操作。
shutil包rmtree()函数就实现了以上功能。shutil是一个高级文件操作的包,实现了文件及文件集合复制与删除的功能。rmtree()函数接收非空文件夹的路径这唯一一个参数。示例代码如下:
import shutil
path = 'g:\'
shutil.rmtree(path)非常感谢您的耐心观看,如有帮助请采纳,祝生活愉快!谢谢!

⑶ Python协程池执行完后怎么回收

学习python可以去专业机构学,还有项目可以实践。更有利于个人未来发展更好

⑷ python的回收机制是什么

Python中的垃圾回收机制总体上有三种,

引用计数

Python语言默认采用的垃圾收集机制是‘引用计数法 Reference Counting’,该算法最早George E. Collins在1960的时候首次提出,50年后的今天,该算法依然被很多编程语言使用,‘引用计数法’的原理是:每个对象维护一个ob_ref字段,用来记录该对象当前被引用的次数,每当新的引用指向该对象时,它的引用计数ob_ref加1,每当该对象的引用失效时计数ob_ref减1,一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。它的缺点是需要额外的空间维护引用计数,这个问题是其次的,不过最主要的问题是它不能解决对象的“循环引用”,因此,也有很多语言比如Java并没有采用该算法做来垃圾的收集机制。

在上图中,我们把小黑圈视为全局变量,也就是把它作为root object,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。

标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

分代回收

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象。

Python垃圾回收机制--完美讲解! 东皇Amrzs

Python中的垃圾回收机制

⑸ python的简单问题

要把代码发现来才知道,以下是常见的错误下面终于要讲到当你用到更多的Python的功能(数据类型,函数,模块,类等等)时可能碰到的问题了。由于篇幅有限,这里尽量精简,尤其是对一些高级的概念。要想了解更多的细节,敬请阅读Learning Python, 2nd Edition的逗小贴士地以及逗Gotchas地章节。 打开文件的调用不使用模块搜索路径当你在Python中调用open()来访问一个外部的文件时,Python不会使用模块搜索路径来定位这个目标文件。它会使用你提供的绝对路径,或者假定这个文件是在当前工作目录中。模块搜索路径仅仅为模块加载服务的。不同的类型对应的方法也不同列表的方法是不能用在字符串上的,反之亦然。通常情况下,方法的调用是和数据类型有关的,但是内部函数通常在很多类型上都可以使用。举个例子来说,列表的reverse方法仅仅对列表有用,但是len函数对任何具有长度的对象都适用不能直接改变不可变数据类型记住你没法直接的改变一个不可变的对象(例如,元组,字符串): T = (1, 2, 3) T[2] = 4 # 错误 用切片,联接等构建一个新的对象,并根据需求将原来变量的值赋给它。因为Python会自动回收没有用的内存,因此这没有看起来那么浪费: T = T[:2] + (4,) # 没问题了: T 变成了 (1, 2, 4) 使用简单的for循环而不是while或者range 当你要从左到右遍历一个有序的对象的所有元素时,用简单的for循环(例如,for x in seq:)相比于基于while-或者range-的计数循环而言会更容易写,通常运行起来也更快。除非你一定需要,尽量避免在一个for循环里使用range:让Python来替你解决标号的问题。在下面的例子中三个循环结构都没有问题,但是第一个通常来说更好;在Python里,简单至上。 S = "lumberjack" for c in S: print c # 最简单 for i in range(len(S)): print S[i] # 太多了 i = 0 # 太多了 while i len(S): print S[i]; i += 1 不要试图从那些会改变对象的函数得到结果诸如像方法list.append()和list.sort()一类的直接改变操作会改变一个对象,但不会将它们改变的对象返回出来(它们会返回None);正确的做法是直接调用它们而不要将结果赋值。经常会看见初学者会写诸如此类的代码: mylist = mylist.append(X) 目的是要得到append的结果,但是事实上这样做会将None赋值给mylist,而不是改变后的列表。更加特别的一个例子是想通过用排序后的键值来遍历一个字典里的各个元素,请看下面的例子: D = {...} for k in D.keys().sort(): print D[k] 差一点儿就成功了——keys方法会创建一个keys的列表,然后用sort方法来将这个列表排序——但是因为sort方法会返回None,这个循环会失败,因为它实际上是要遍历None(这可不是一个序列)。要改正这段代码,将方法的调用分离出来,放在不同的语句中,如下: Ks = D.keys() Ks.sort() for k in Ks: print D[k] 只有在数字类型中才存在类型转换在Python中,一个诸如123+3.145的表达式是可以工作的——它会自动将整数型转换为浮点型,然后用浮点运算。但是下面的代码就会出错了: S = "42" I = 1 X = S + I # 类型错误 这同样也是有意而为的,因为这是不明确的:究竟是将字符串转换为数字(进行相加)呢,还是将数字转换为字符串(进行联接)呢看在Python中,我们认为逗明确比含糊好地(即,EIBTI(Explicit is better than implicit)),因此你得手动转换类型: X = int(S) + I # 做加法: 43 X = S + str(I) # 字符串联接: "421" 循环的数据结构会导致循环尽管这在实际情况中很少见,但是如果一个对象的集合包含了到它自己的引用,这被称为循环对象(cyclic object)。如果在一个对象中发现一个循环,Python会输出一个[…],以避免在无限循环中卡住: >>> L = ['grail'] # 在 L中又引用L自身会 >>> L.append(L) # 在对象中创造一个循环 >>> L ['grail', [...]] 除了知道这三个点在对象中表示循环以外,这个例子也是很值得借鉴的。因为你可能无意间在你的代码中出现这样的循环的结构而导致你的代码出错。如果有必要的话,维护一个列表或者字典来表示已经访问过的对象,然后通过检查它来确认你是否碰到了循环。赋值语句不会创建对象的副本,仅仅创建引用这是Python的一个核心理念,有时候当行为不对时会带来错误。在下面的例子中,一个列表对象被赋给了名为L的变量,然后L又在列表M中被引用。内部改变L的话,同时也会改变M所引用的对象,因为它们俩都指向同一个对象。 >>> L = [1, 2, 3] # 共用的列表对象 >>> M = ['X', L, 'Y'] # 嵌入一个到L的引用 >>> M ['X', [1, 2, 3], 'Y'] >>> L[1] = 0 # 也改变了M >>> M ['X', [1, 0, 3], 'Y'] 通常情况下只有在稍大一点的程序里这就显得很重要了,而且这些共用的引用通常确实是你需要的。如果不是的话,你可以明确的给他们创建一个副本来避免共用的引用;对于列表来说,你可以通过使用一个空列表的切片来创建一个顶层的副本: >>> L = [1, 2, 3] >>> M = ['X', L[:], 'Y'] # 嵌入一个L的副本 >>> L[1] = 0 # 仅仅改变了L,但是不影响M >>> L [1, 0, 3] >>> M ['X', [1, 2, 3], 'Y'] 切片的范围起始从默认的0到被切片的序列的最大长度。如果两者都省略掉了,那么切片会抽取该序列中的所有元素,并创造一个顶层的副本(一个新的,不被公用的对象)。对于字典来说,使用字典的dict.()方法。静态识别本地域的变量名 Python默认将一个函数中赋值的变量名视作是本地域的,它们存在于该函数的作用域中并且仅仅在函数运行的时候才存在。从技术上讲,Python是在编译def代码时,去静态的识别本地变量,而不是在运行时碰到赋值的时候才识别到的。如果不理解这点的话,会引起人们的误解。比如,看看下面的例子,当你在一个引用之后给一个变量赋值会怎么样: >>> X = 99 >>> def func(): ... print X # 这个时候还不存在 ... X = 88 # 在整个def中将X视作本地变量 ... >>> func( ) # 出错了! 你会得到一个逗未定义变量名地的错误,但是其原因是很微妙的。当编译这则代码时,Python碰到给X赋值的语句时认为在这个函数中的任何地方X会被视作一个本地变量名。但是之后当真正运行这个函数时,执行print语句的时候,赋值语句还没有发生,这样Python便会报告一个逗未定义变量名地的错误。事实上,之前的这个例子想要做的事情是很模糊的:你是想要先输出那个全局的X,然后创建一个本地的X呢,还是说这是个程序的错误看如果你真的是想要输出这个全局的X,你需要将它在一个全局语句中声明它,或者通过包络模块的名字来引用它。默认参数和可变对象在执行def语句时,默认参数的值只被解析并保存一次,而不是每次在调用函数的时候。这通常是你想要的那样,但是因为默认值需要在每次调用时都保持同样对象,你在试图改变可变的默认值(mutable defaults)的时候可要小心了。例如,下面的函数中使用一个空的列表作为默认值,然后在之后每一次函数调用的时候改变它的值: >>> def saver(x=[]): # 保存一个列表对象 ... x.append(1) # 并每次调用的时候 ... print x # 改变它的值 ... >>> saver([2]) # 未使用默认值 [2, 1] >>> saver() # 使用默认值 [1] >>> saver() # 每次调用都会增加! [1, 1] >>> saver() [1, 1, 1] 有的人将这个视作Python的一个特点——因为可变的默认参数在每次函数调用时保持了它们的状态,它们能提供像C语言中静态本地函数变量的类似的一些功能。但是,当你第一次碰到它时会觉得这很奇怪,并且在Python中有更加简单的办法来在不同的调用之间保存状态(比如说类)。要摆脱这样的行为,在函数开始的地方用切片或者方法来创建默认参数的副本,或者将默认值的表达式移到函数里面;只要每次函数调用时这些值在函数里,就会每次都得到一个新的对象: >>> def saver(x=None): ... if x is None: x = [] # 没有传入参数看 ... x.append(1) # 改变新的列表 ... print x ... >>> saver([2]) # 没有使用默认值 [2, 1] >>> saver() # 这次不会变了 [1] >>> saver() [1] 其他常见的编程陷阱下面列举了其他的一些在这里没法详述的陷阱:在顶层文件中语句的顺序是有讲究的:因为运行或者加载一个文件会从上到下运行它的语句,所以请确保将你未嵌套的函数调用或者类的调用放在函数或者类的定义之后。 reload不影响用from加载的名字:reload最好和import语句一起使用。如果你使用from语句,记得在reload之后重新运行一遍from,否则你仍然使用之前老的名字。在多重继承中混合的顺序是有讲究的:这是因为对superclass的搜索是从左到右的,在类定义的头部,在多重superclass中如果出现重复的名字,则以最左边的类名为准。在try语句中空的except子句可能会比你预想的捕捉到更多的错误。在try语句中空的except子句表示捕捉所有的错误,即便是真正的程序错误,和sys.exit()调用,也会被捕捉到。

⑹ Python的垃圾回收机制(garbage collection)是什么

这里能说的很多。你应该提到下面几个主要的点:

Python在内存中存储了每个对象的引用计数(reference count)。如果计数值变成0,那么相应的对象就会小时,分配给该对象的内存就会释放出来用作他用。

偶尔也会出现引用循环(reference cycle)。垃圾回收器会定时寻找这个循环,并将其回收。举个例子,假设有两个对象o1和o2,而且符合o1.x == o2和o2.x == o1这两个条件。如果o1和o2没有其他代码引用,那么它们就不应该继续存在。但它们的引用计数都是1。来自三人行慕课

Python中使用了某些启发式算法(heuristics)来加速垃圾回收。例如,越晚创建的对象更有可能被回收。对象被创建之后,垃圾回收器会分配它们所属的代(generation)。每个对象都会被分配一个代,而被分配更年轻代的对象是优先被处理的。

⑺ Python垃圾回收机制是什么样的

Python垃圾回收机制是通过引用计数来管理的引用计数表示记录这个对象被引用的次数如果有新的引用指向对象,对象引用计数就加一,引用被销毁时,对象引用计数减一,当用户的引用计数为0时,该内存被释放以上就是Python的垃圾回收机制了 ,在黑马程序员看过一个视频,有专门讲解的,你可以去看看!谢谢你,如果你有这方面的问题的话,您可以随时询问我

⑻ Python里的垃圾回收机制是什么意思,搞不懂

如果你用C++写程序的话 有时候需要动态内存 就是在你需要的时候给你分配空间 但是如果你忘记把它释放或者你把指向那块内存的指针给搞丢了,那么那块内存就不能够再使用。如果你的程序不断的申请但又不释放内存,那么电脑内存的使用就越来越高。最后直接99% 程序崩溃电脑卡死
但是java就不会了 她回主动帮你释放不用的内存 就是垃圾回收机制 但是这个回收时间 回收哪里也是有讲究的,这里就不细说了。
总之,java比其他语言比如c c++安全 但是相应的效率就没有那么高了
程序 就是个时间空间的交换游戏嘛!

⑼ 为什么Python工程师很少像Java工程师那样讨论垃圾回收

Python本身的垃圾回收机制优化得非常好,一般来讲,不需要再做单独处理,这也是Python的一大优势。

⑽ python 什么时候 垃圾回收

Python中的垃圾回收是以引用计数为主,分代收集为辅。引用计数的缺陷是循环引用的问题。
在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存。
#encoding=utf-8
__author__ = '[email protected]'

class ClassA():
def __init__(self):
print 'object born,id:%s'%str(hex(id(self)))
def __del__(self):
print 'object del,id:%s'%str(hex(id(self)))

def f1():
while True:
c1=ClassA()
del c1

执行f1()会循环输出这样的结果,而且进程占用的内存基本不会变动
object born,id:0x237cf58
object del,id:0x237cf58

c1=ClassA()会创建一个对象,放在0x237cf58内存中,c1变量指向这个内存,这时候这个内存的引用计数是1
del c1后,c1变量不再指向0x237cf58内存,所以这块内存的引用计数减一,等于0,所以就销毁了这个对象,然后释放内存。
1、导致引用计数+1的情况

对象被创建,例如a=23
对象被引用,例如b=a
对象被作为参数,传入到一个函数中,例如func(a)
对象作为一个元素,存储在容器中,例如list1=[a,a]

2、导致引用计数-1的情况

对象的别名被显式销毁,例如del a
对象的别名被赋予新的对象,例如a=24
一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
对象所在的容器被销毁,或从容器中删除对象

demo
def func(c,d):
print 'in func function', sys.getrefcount(c) - 1

print 'init', sys.getrefcount(11) - 1
a = 11
print 'after a=11', sys.getrefcount(11) - 1
b = a
print 'after b=1', sys.getrefcount(11) - 1
func(11)
print 'after func(a)', sys.getrefcount(11) - 1
list1 = [a, 12, 14]
print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
a=12
print 'after a=12', sys.getrefcount(11) - 1
del a
print 'after del a', sys.getrefcount(11) - 1
del b
print 'after del b', sys.getrefcount(11) - 1
# list1.pop(0)
# print 'after pop list1',sys.getrefcount(11)-1
del list1
print 'after del list1', sys.getrefcount(11) - 1

输出
init 24
after a=11 25
after b=1 26
in func function 28
after func(a) 26
after list1=[a,12,14] 27
after a=12 26
after del a 26
after del b 25
after del list1 24

问题:为什么调用函数会令引用计数+2
3、查看一个对象的引用计数
sys.getrefcount(a)可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1
二.循环引用导致内存泄露

def f2():
while True:
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2

执行f2(),进程占用的内存会不断增大。
object born,id:0x237cf30
object born,id:0x237cf58

创建了c1,c2后,0x237cf30(c1对应的内存,记为内存1),0x237cf58(c2对应的内存,记为内存2)这两块内存的引用计数都是1,执行c1.t=c2和c2.t=c1后,这两块内存的引用计数变成2.
在del c1后,内存1的对象的引用计数变为1,由于不是为0,所以内存1的对象不会被销毁,所以内存2的对象的引用数依然是2,在del c2后,同理,内存1的对象,内存2的对象的引用数都是1。
虽然它们两个的对象都是可以被销毁的,但是由于循环引用,导致垃圾回收器都不会回收它们,所以就会导致内存泄露。
三.垃圾回收

deff3():
# print gc.collect()
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2
print gc.garbage
print gc.collect() #显式执行垃圾回收
print gc.garbage
time.sleep(10)
if __name__ == '__main__':
gc.set_debug(gc.DEBUG_LEAK) #设置gc模块的日志
f3()

输出:
gc: uncollectable <ClassA instance at 0230E918>
gc: uncollectable <ClassA instance at 0230E940>
gc: uncollectable <dict 0230B810>
gc: uncollectable <dict 02301ED0>
object born,id:0x230e918
object born,id:0x230e940
4

垃圾回收后的对象会放在gc.garbage列表里面
gc.collect()会返回不可达的对象数目,4等于两个对象以及它们对应的dict
有三种情况会触发垃圾回收:

1.调用gc.collect(),
2.当gc模块的计数器达到阀值的时候。
3.程序退出的时候
四.gc模块常用功能解析
gc模块提供一个接口给开发者设置垃圾回收的选项。上面说到,采用引用计数的方法管理内存的一个缺陷是循环引用,而gc模块的一个主要功能就是解决循环引用的问题。
常用函数:
1、gc.set_debug(flags)
设置gc的debug日志,一般设置为gc.DEBUG_LEAK
2、gc.collect([generation])
显式进行垃圾回收,可以输入参数,0代表只检查第一代的对象,1代表检查一,二代的对象,2代表检查一,二,三代的对象,如果不传参数,执行一个full collection,也就是等于传2。
返回不可达(unreachable objects)对象的数目
3、gc.set_threshold(threshold0[, threshold1[, threshold2])
设置自动执行垃圾回收的频率。
4、gc.get_count()
获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表
5、gc模块的自动垃圾回收机制
必须要import gc模块,并且is_enable()=True才会启动自动垃圾回收。
这个机制的主要作用就是发现并处理不可达的垃圾对象。
垃圾回收=垃圾检查+垃圾回收
在Python中,采用分代收集的方法。把对象分为三代,一开始,对象在创建的时候,放在一代中,如果在一次一代的垃圾检查中,改对象存活下来,就会被放到二代中,同理在一次二代的垃圾检查中,该对象存活下来,就会被放到三代中。
gc模块里面会有一个长度为3的列表的计数器,可以通过gc.get_count()获取。
例如(488,3,0),其中488是指距离上一次一代垃圾检查,Python分配内存的数目减去释放内存的数目,注意是内存分配,而不是引用计数的增加。例如:
print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)

3是指距离上一次二代垃圾检查,一代垃圾检查的次数,同理,0是指距离上一次三代垃圾检查,二代垃圾检查的次数。
gc模快有一个自动垃圾回收的阀值,即通过gc.get_threshold函数获取到的长度为3的元组,例如(700,10,10)
每一次计数器的增加,gc模块就会检查增加后的计数是否达到阀值的数目,如果是,就会执行对应的代数的垃圾检查,然后重置计数器
例如,假设阀值是(700,10,10):
当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)
当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)
当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,0)

热点内容
用近似归算法 发布:2025-01-21 00:51:56 浏览:517
php显示数据库中图片 发布:2025-01-21 00:44:34 浏览:146
如何在服务器中找文件 发布:2025-01-21 00:38:50 浏览:911
Cmdpython命令 发布:2025-01-21 00:30:38 浏览:758
mac常用解压 发布:2025-01-21 00:01:47 浏览:692
linuxcpu使用 发布:2025-01-21 00:00:59 浏览:850
成套供应配电柜有哪些配置 发布:2025-01-21 00:00:52 浏览:121
GO编译器PDF 发布:2025-01-21 00:00:52 浏览:704
osu上传成绩 发布:2025-01-20 23:59:57 浏览:642
了解sql 发布:2025-01-20 23:58:39 浏览:656