python tracemalloc 模块分配统计数据何时会与 ps 或 pmap 中显示的不匹配?

When would the python tracemalloc module allocations statistics not match what's shown in ps or pmap?

我正在尝试追踪内存泄漏,所以我已经完成了

import tracemalloc
tracemalloc.start()

<function call>

# copy pasted this from documentation
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

print("[ Top 10 ]")
for stat in top_stats[:10]:
    print(stat)

这表明没有主要分配,所有内存分配都非常小,而我看到在 pspmap 中分配了 8+ GB 内存(检查 运行 之前和之后命令,以及 运行 垃圾回收之后)。此外,tracemalloc.get_traced_memory 确认 tracemalloc 没有看到很多分配。 pympler 也没有看到分配。

有谁知道什么时候会出现这种情况?一些模块正在使用 cython,这会导致 tracemalloc 出现问题吗?

在 pmap 中,分配如下所示:

0000000002183000 6492008 6491876 6491876 rw--- [ anon ]

来自 tracemalloc 上的文档:

The tracemalloc module is a debug tool to trace memory blocks allocated by Python.

换句话说,tracemalloc 看不到未由 python 解释器分配的内存。这将包括 PyMalloc 在 C-API 级别未完成的任何事情,包括通过扩展使用的本机代码或直接使用 malloc 的扩展代码的所有标准 libc malloc 调用.

如果没有代码重现,就无法确定这里是否是这种情况。您可以尝试 运行 python 之外的本机代码部分,例如通过 valgrind 来检测本机代码中的内存泄漏。

如果有 cython 代码在做 malloc,可以切换到 PyMalloc 来跟踪它。

@danny 的回答的补充,因为评论太长了。

PEP-464, tracemalloc uses functionality introduced in PEP-445 中所述,用于跟踪内存分配。

通常,人们必须使用 PyMem_RawMalloc instead of malloc in order to be able to use tracemalloc for a C-extension. However, since quite some time also using PyTraceMalloc_Track and PyTraceMalloc_Untrack from pymem.h 作为 malloc 的补充(而不是用 PyMem_RawMalloc 代替)。

这就是在 numpy 中使用的示例,因为为了能够包装原始 c 指针并接管其所有权,numpy 使用了 malloc 而不是 python-allocator ,它针对小对象进行了优化 - 不是 numpy 最关键的场景,可以看出 here:

/*NUMPY_API
 * Allocates memory for array data.
 */
NPY_NO_EXPORT void *
PyDataMem_NEW(size_t size)
{
    void *result;

    result = malloc(size);
    if (_PyDataMem_eventhook != NULL) {
        NPY_ALLOW_C_API_DEF
        NPY_ALLOW_C_API
        if (_PyDataMem_eventhook != NULL) {
            (*_PyDataMem_eventhook)(NULL, result, size,
                                    _PyDataMem_eventhook_user_data);
        }
        NPY_DISABLE_C_API
    }
    PyTraceMalloc_Track(NPY_TRACE_DOMAIN, (npy_uintp)result, size);
    return result;
}

所以基本上,C 扩展有责任向 tracemalloc 模块报告内存分配,另一方面,tracemalloc 不能真正信任注册所有内存分配。