第十七章:运行时特性-gc:垃圾回收器-调试

17.6.5 调试
调试内存泄漏可能很有难度。gc包括有一些选项,可以提供代码的内部工作情况,使这个任务更为简单。这些选项都是位标志,可以组合传递到set_debug(),在程序运行时配置垃圾回收器。调试信息被打印到sys.stderr。
DEBUG_STATS标志打开统计报告。这会使垃圾回收器报告它何时运行、每一代跟踪的对象数以及完成清扫花费的时间。

import gc

gc.set_debug(gc.DEBUG_STATS)

gc.collect()
print('Exiting')

这个示例输出显示运行了两次回收器。第一次是在显式调用时运行,第二次是在解释器退出时运行。
第十七章:运行时特性-gc:垃圾回收器-调试_第1张图片
启用DEBUG_COLLECTABLE和DEBUG_UNCOLLECTABLE会让回收器报告它检查的各个对象能不能回收。如果看到不能回收的对象,但这还不能提供足够的信息来了解数据保留在哪里,则可以启用DEBUG_SAVEALL,这会让gc保留它找到的所有对象,但在garbage列表中没有任何引用。

import gc

flags = (gc.DEBUG_COLLECTABLE |
         gc.DEBUG_UNCOLLECTABLE |
         gc.DEBUG_SAVEALL
         )

gc.set_debug(flags)


class Graph:

    def __init__(self,name):
        self.name = name
        self.next = None

    def set_next(self,next):
        self.next = next
        
    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__,self.name)


class CleanupGraph(Graph):

    def __del__(self):
        print('{}.__del__()'.format(self))


# Construct a graph cycle.
one = Graph('one')
two = Graph('two')
one.set_next(two)
two.set_next(one)

# Construct another node that stands on its own.
three = CleanupGraph('three')
# Construct a graph cycle with a finalizer.
four = CleanupGraph('four')
five = CleanupGraph('five')
four.set_next(five)
five.set_next(four)

# Remove references to the graph nodes in this module's namespace.
one = two = three = fouor = five = None

# Force a sweep.
print('Collecting')
gc.collect()
print('Done')

# Report on what was left.
for o in gc.garbage:
    if isinstance(o,Graph):
        print('Retained: {} 0x{:x}'.format(o,id(o)))

# Reset the debug flags before exiting to avoid dumping a lot
# of extra information and making the example output more
# confusing.
gc.set_debug(0)

这个代码允许在垃圾回收后检查对象,有些情况下这会很有用,例如,不能把构造函数改为在创建各个对象时打印对象ID。
第十七章:运行时特性-gc:垃圾回收器-调试_第2张图片
为简单起见,DEBUG_LEAK被定义为所有其他选项的一个组合。

import gc

flags = gc.DEBUG_LEAK

gc.set_debug(flags)


class Graph:

    def __init__(self,name):
        self.name = name
        self.next = None

    def set_next(self,next):
        self.next = next

    def __repr__(self):
        return '{}({})'.format(
            self.__class__.__name__,self.name)


class CleanupGraph(Graph):

    def __del__(self):
        print('{}.__del__()'.format(self))


# Construct a graph cycle.
one = Graph('one')
two = Graph('two')
one.set_next(two)
two.set_next(one)

# Construct another node that stands on its own.
three = CleanupGraph('three')

# Construct a graph cycle with a finalizer.
four = CleanupGraph('four')
five = CleanupGraph('five')
four.set_next(five)
five.set_next(four)

# Remove references to the graph nodes in this module's namespace.
one = two = three = four = five = None

# Force a sweep.
print('Collecting')
gc.collect()
print('Done')

# Report on what was left.
for o in gc.garbage:
    if isinstance(o,Graph):
        print('Retained: {} 0x{:x}'.format(o,id(o)))

# Reset the debug flags before exiting to avoid dumping a lot
# of extra information and making the example output more
# confusing.
gc.set_debug(0)

要记住,由于DEBUG_SAVEALL由DEBUG_LEAK启用,甚至正常情况下已经被回收和删除的无引用的对象也会保留。
第十七章:运行时特性-gc:垃圾回收器-调试_第3张图片

你可能感兴趣的:(Python标准库)