我正在阅读documentation for Memory Management in Python C extensions,据我所知,似乎没有太多理由使用malloc
而不是PyMem_Malloc
。假设我想分配一个不暴露给Python源代码的数组,并将存储在一个将被垃圾收集的对象中。有没有理由使用malloc
?
答案 0 :(得分:7)
扩展使用malloc或其他系统分配器分配内存是完全可以的。对于许多类型的模块而言,这是正常且不可避免的 - 大多数包装其他库的模块,它们本身对Python一无所知,当它们在该库中发生时将导致本机分配。 (有些库允许您控制分配足以防止这种情况;大多数库都没有。)
使用PyMem_Malloc有一个严重的缺点:使用它时需要保持GIL。本机库通常希望在进行CPU密集型计算或进行任何可能阻塞的调用(如I / O)时释放GIL。需要在分配之前锁定GIL可能介于非常不方便和性能问题之间。
使用Python的包装器进行内存分配,可以使用Python的内存调试代码。有了像Valgrind这样的工具,我怀疑它的真实世界价值。
如果API需要,您需要使用这些功能;例如,如果API传递了必须使用这些函数分配的指针,那么可以使用它们释放它。除非有明确的理由使用它们,否则我坚持正常分配。
答案 1 :(得分:6)
编辑:混合PyMem_Malloc
和PyObject_Malloc
更正;他们是两个不同的电话。
如果没有激活PYMALLOC_DEBUG
宏,PyMem_Malloc
是libc的malloc()
的别名,有一个特殊情况:调用PyMem_Malloc
分配零字节将返回非NULL指针,而malloc(zero_bytes)可能返回NULL值或引发系统错误(source code reference):
/ * malloc。请注意,nbytes == 0次尝试 返回非NULL指针,不同 *来自所有其他当前现场指针。这可能是不可能的。 * /
另外,pymem.h
header file上有一条咨询说明:
永远不要混淆与PyMem_的调用 调用平台malloc / realloc / 释放calloc /免费。例如,在Windows上 不同的DLL最终可能会使用 不同的堆,如果你使用 PyMem_Malloc你会得到记忆 来自Python使用的堆 DLL;如果你这可能是一场灾难 free()'直接在你自己的 延期。改为使用PyMem_Free 确保Python可以返回 内存到正确的堆。另一个 例如,在PYMALLOC_DEBUG模式中, Python包装对所有PyMem_的所有调用 和PyObject_内存函数 添加的特殊调试包装器 额外的调试信息 动态内存块。系统 例程不知道该怎么做 用那些东西和Python 包装工人不知道该怎么做 用直接获得的原始块 那么系统例程。
然后, PyMem_Malloc
PyObject_Malloc
中有一些Python特定的调优,这个函数不仅用于C扩展,还用于运行Python程序时的所有动态分配,例如100*234
,str(100)
或10 + 4j
:
>>> id(10 + 4j)
139721697591440
>>> id(10 + 4j)
139721697591504
>>> id(10 + 4j)
139721697591440
以前的complex()
实例是在专用池上分配的小对象。
使用 PyMem_Malloc
PyObject_Malloc
分配小对象(< 256字节)是非常有效的,因为它是从池中8字节对齐的块完成的,每个块现有一个池尺寸。还有Pages和Arenas块用于更大的分配。
source code上的这条评论解释了PyObject_Malloc
调用的优化方式:
/*
* The basic blocks are ordered by decreasing execution frequency,
* which minimizes the number of jumps in the most common cases,
* improves branching prediction and instruction scheduling (small
* block allocations typically result in a couple of instructions).
* Unless the optimizer reorders everything, being too smart...
*/
Pools,Pages和Arenas是旨在减少长期运行的Python程序external memory fragmentation的优化。
查看the source code以获取有关Python内存内部的完整详细文档。
答案 2 :(得分:1)
根据我编写MATLAB .mex函数的经验,我认为你是否使用malloc的最大决定因素是可移植性。假设您有一个头文件,它只使用内部c数据类型执行大量有用的功能(没有必要的Python对象交互,所以使用malloc没问题),你突然意识到你想要将该头文件移植到另一个代码库中与Python无关(也许这是一个纯粹用C语言编写的项目),使用malloc显然是一个更加便携的解决方案。
但是对于纯粹是Python扩展的代码,我最初的反应是期望本机c函数执行得更快。我没有证据支持这一点:)