什么情况存在内存泄露
- python引用计数 + 分代收集和标记清除(处理循环引用),进行垃圾回收,但如下两种情况依旧存在内存泄露:
- 第一是对象被另一个生命周期特别长(如全局变量)的对象所引用
- 第二是循环引用中的对象定义了
__del__函数,简而言之,循环引用中Python无法判断析构对象的顺序,无法释放
相关术语
- reachable/collectable(unreachable/uncollectable)
- reachable是针对python对象而言,如果从根集(root)能到找到对象,那么这个对象就是reachable,与之相反就是unreachable,unreachable只存在于循环引用中的对象,Python的gc模块就是针对unreachable对象
- collectable是针对unreachable对象而言,如果这种对象能被回收,是collectable,如果不能被回收,即循环引用中的对象定义了
__del__, 那么就是uncollectable。 即unreachable (循环引用)分成 collectable和ubcollectable(__del__)
GC模块
This module provides access to the garbage collector for reference cycles.
enable() -- Enable automatic garbage collection.
disable() -- Disable automatic garbage collection.
isenabled() -- Returns true if automatic collection is enabled.
collect() -- Do a full collection right now. Tg
gc.set_debug(flags)
gc.DEBUG_COLLETABLE: 打印可以被垃圾回收器回收的对象
gc.DEBUG_UNCOLLETABLE: 打印无法被垃圾回收器回收的对象,即定义了__del__的对象
gc.DEBUG_SAVEALL:所有的unreachable对象都将加入gc.garbage返回的列表
gc.garbage: 返回是unreachable对象,且不能被回收的的对象,如果设置SAVEALL,所有unreachable都加入此列表
A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects). Starting with Python 3.4, this list should be empty most of the time, except when using instances of C extension types with a non-NULL tp_del slot.
禁用GC
只要能手动解决循环引用,就可以禁止GC模块来提高效率,因为GC适用于循环引用的垃圾回收机制。 如果可以确定代码没有循环引用,那么可以禁用GC模块
特殊说明(PEP442)
python3.4开始已经可以自动处理带有__del__方法的循环引用,也不会发生内存泄露了
import gc
class Foo(object):
def __init__(self):
self.bar = None
print('foo init')
def __del__(self):
print("foo del")
class Bar(object):
def __init__(self):
self.foo = None
print('bar init')
def __del__(self):
print('bar del')
def collect_and_show_garbage():
print("Collecting...")
n = gc.collect()
print("unreachable objects:", n)
print(gc.garbage)
def func():
foo = Foo()
bar = Bar()
foo.bar = bar
bar.foo = foo
# gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE)
func()
collect_and_show_garbage()
python2.7
foo init
bar init
Collecting…
(‘unreachable objects:’, 4)
[<main.Foo object at 0x101235550>, <main.Bar object at 0x1012355d0>]python3.6
foo init
bar init
Collecting…
foo del
bar del
unreachable objects: 4
[]
gc.collect() 返回unreachable的数目,所以无论2.7还是3.6都一样,但、3.6中可以处理循环引用且带有__del__的情况,所以gc.garbage为空,当然如果没有__del__方法,2.7中gc.garbage也是空
本文探讨了Python中的内存泄露问题,特别是由于全局变量引用和循环引用导致的情况。介绍了Python的垃圾回收机制,包括引用计数、分代收集和标记清除。详细阐述了可达性和不可达对象的概念,并讲解了如何使用GC模块进行调试,如设置DEBUG_COLLETABLE和DEBUG_UNCOLLETABLE标志。从Python 3.4开始,PEP442使得带有方法的循环引用能得到自动处理,减少了内存泄露的发生。

5094

被折叠的 条评论
为什么被折叠?



