Python中内存泄漏的单元测试



有没有办法在Python中运行内存泄漏单元测试?我已经编写了一些C++绑定代码,希望确保它不会泄露内存。

例如,我想要一个如下的测试:

memory_usage_0 = 0
memory_usage_1 = 0
memory_usage_0 = get_memory_usage()
do_cpp_bound_operation()
memory_usage_1 = get_memory_usage()
assert memory_usage_0 == memory_usage_1

如果您希望您的单元测试速度较慢,下面是基于您的编码示例进行尝试的方法:

将您的代码片段更改为如下所示:

gc.collect()
callCppCoreGenerationFunction()
do_cpp_bound_operation()
gc.collect()
callCppCoreGenerationFunction()
compareCores()

您的callCppCoreGenerationFunction可以调用一个c或c++函数,该函数就像分叉一个新进程并让子进程自行终止一样简单,例如,让子进程引用一个空指针。关键是要简单,因为您不希望这个函数在核心生成过程中进行额外的python分配,从而搅乱局面。

这里要讨论的关键部分是compareRes((。为此,您可以使用分叉进程的标准python代码,因为您已经有了要比较的核心,不需要担心扭曲结果。例如,您可以派生一个shell脚本来计算您的答案。

所以现在的问题是shell脚本中应该包含什么。它应该做的第一件事是按照创建的顺序列出核心,这样你就可以比较最近的两个。然后在chap中打开每个核心(可在https://github.com/vmware/chap)。对于每个核心,你应该在chap中打开它,并从chap提示符运行以下命令:

count leaked

这看起来像这样,将捕获泄漏的本地分配对象和一些(但肯定不是全部(泄漏的python对象。

chap> count leaked
0 allocations use 0x0 (0) bytes.

这个特定的命令非常可靠,因为chap的设计目的是避免泄漏时出现误报。因此,您甚至可以只在两个核心中的第二个核心上运行此操作,而根本不需要第一个核心进行这样的检查。如果你确实发现泄漏是其他可以用来分析泄漏的chap命令,但如果你只想知道你是否有这样的泄漏,而不是为什么,那么计数就足够了。

describe used

这将描述所有已分配但未释放的分配(python和本机(。它的输出看起来像这样,但有更多的行:

Anchored allocation at 7f505b117630 of size 40
This allocation matches pattern ContainerPythonObject.
This has a PyGC_Head at the start so the real PyObject is at offset 0x10.
This has reference count 1 and python type 0x903f20 (dict)
Anchored allocation at 7f505b117670 of size 40
This allocation matches pattern ContainerPythonObject.
This has a PyGC_Head at the start so the real PyObject is at offset 0x10.
This has reference count 1 and python type 0x8fd660 (list)
Anchored allocation at 16f8a80 of size 238
This allocation matches pattern SimplePythonObject.
This has reference count 1 and python type 0x7f5e824cdfe0 (str)
This has a string of length 512 starting with
"bytearray(iterable_of_ints) -> bytearray
bytearray(string, encoding[, errors]".

在该输出中;是像str这样的python对象,它不引用其他python对象ContainerPython对象";是一个可以引用其他python对象的python对象,因此会受到垃圾收集。

请注意,每个这样的对象的python引用计数都是给定的。这意味着,在回答您关于检查c++代码是否错误地进行了引用计数的问题时,这将反映在输出文件中给定对象的引用计数的更改中。因此,可以通过这种方式捕获小到单个引用计数错误的错误,从而导致泄漏。

%SimplePythonObject通常可以被检测为泄漏,只需使用";计数泄漏";对于一个核心,只要没有分配(python或native或…(仍然引用它;描述使用的";更通用,并为您的用例提供更好的覆盖范围。

最新更新