有没有理由在PyMem_Malloc上使用malloc?

时间:2011-01-27 23:09:45

标签: python c malloc python-c-extension

我正在阅读documentation for Memory Management in Python C extensions,据我所知,似乎没有太多理由使用malloc而不是PyMem_Malloc。假设我想分配一个不暴露给Python源代码的数组,并将存储在一个将被垃圾收集的对象中。有没有理由使用malloc

3 个答案:

答案 0 :(得分:7)

扩展使用malloc或其他系统分配器分配内存是完全可以的。对于许多类型的模块而言,这是正常且不可避免的 - 大多数包装其他库的模块,它们本身对Python一无所知,当它们在该库中发生时将导致本机分配。 (有些库允许您控制分配足以防止这种情况;大多数库都没有。)

使用PyMem_Malloc有一个严重的缺点:使用它时需要保持GIL。本机库通常希望在进行CPU密集型计算或进行任何可能阻塞的调用(如I / O)时释放GIL。需要在分配之前锁定GIL可能介于非常不方便和性能问题之间。

使用Python的包装器进行内存分配,可以使用Python的内存调试代码。有了像Valgrind这样的工具,我怀疑它的真实世界价值。

如果API需要,您需要使用这些功能;例如,如果API传递了必须使用这些函数分配的指针,那么可以使用它们释放它。除非有明确的理由使用它们,否则我坚持正常分配。

答案 1 :(得分:6)

编辑:混合PyMem_MallocPyObject_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*234str(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函数执行得更快。我没有证据支持这一点:)