3xt*_*ter 7 python garbage-collection exec
我发现了一个问题exec(它发生在一个必须可以用用户编写的脚本扩展的系统中).我可以将问题本身减少到这段代码:
def fn():
context = {}
exec '''
class test:
def __init__(self):
self.buf = '1'*1024*1024*200
x = test()''' in context
fn()
Run Code Online (Sandbox Code Playgroud)
我希望在调用函数后,垃圾收集器应该释放内存fn.但是,Python进程仍然消耗额外的200MB内存,我完全不知道这里发生了什么以及如何手动释放分配的内存.
我怀疑在里面定义一个类exec并不是一个非常明智的想法,但首先,我想了解上面例子中出了什么问题.
看起来在另一个函数中创建包装类实例可以解决问题,但有什么区别?
def fn():
context = {}
exec '''
class test:
def __init__(self):
self.buf = '1'*1024*1024*200
def f1(): x = test()
f1()
''' in context
fn()
Run Code Online (Sandbox Code Playgroud)
这是我的Python解释器版本:
$ python
Python 2.7 (r27:82500, Sep 16 2010, 18:02:00)
[GCC 4.5.1 20100907 (Red Hat 4.5.1-3)] on linux2
Run Code Online (Sandbox Code Playgroud)
那你看到它占用200MB的内存比预期的更长的原因是因为你有一个参考周期:context是一个字典引用都x和test.x引用的实例test,其引用test.test有一个属性的字典test.__dict__,它包含__init__类的功能.该__init__函数依次引用它所定义的全局变量 - 这是你传递给的字典exec,context.
Python将为您打破这些参考周期(因为没有任何涉及的__del__方法),但它需要gc.collect()运行.gc.collect()将自动运行每N次分配(确定gc.set_threshold()),因此"泄漏"将在某一时刻消失,但如果您希望它立即消失,您可以gc.collect()自己运行,或者在退出函数之前自行中断参考循环.您可以通过调用轻松完成后者context.clear()- 但您应该意识到这会影响您在其中创建的类的所有实例.
| 归档时间: |
|
| 查看次数: |
500 次 |
| 最近记录: |