Jas*_*ker 8 c python malloc python-c-extension
我正在阅读Python C扩展中的内存管理文档,据我所知,似乎没有太多理由使用malloc而不是PyMem_Malloc.假设我想分配一个不暴露给Python源代码的数组,并将存储在一个将被垃圾收集的对象中.有什么理由可以使用malloc吗?
扩展使用malloc或其他系统分配器分配内存是完全可以的.对于许多类型的模块而言,这是正常的,也是不可避免的 - 大多数包装其他库的模块,它们本身对Python一无所知,当它们在该库中发生时将导致本机分配.(有些库允许您控制分配足以防止这种情况;大多数库不允许.)
使用PyMem_Malloc有一个严重的缺点:你需要在使用它时持有GIL.本机库通常希望在进行CPU密集型计算或进行任何可能阻塞的调用(如I/O)时释放GIL.需要在分配之前锁定GIL可能介于非常不方便和性能问题之间.
使用Python的包装器进行内存分配允许使用Python的内存调试代码.有了像Valgrind这样的工具,我怀疑它的真实世界价值.
如果API需要,您将需要使用这些功能; 例如,如果API传递了必须使用这些函数分配的指针,那么可以使用它们释放它.除非使用它们这样明确的原因,我坚持正常分配.
编辑:混合PyMem_Malloc和PyObject_Malloc更正; 他们是两个不同的电话.
没有PYMALLOC_DEBUG激活宏,PyMem_Malloc是libc的别名malloc(),有一个特殊情况:调用PyMem_Malloc分配零字节将返回非NULL指针,而malloc(zero_bytes)可能返回NULL值或引发系统错误(源代码引用):
/*malloc.请注意,nbytes == 0尝试返回非NULL指针,与所有其他当前活动指针不同.这可能是不可能的.*/
此外,还有一个关于pymem.h头文件的咨询说明:
切勿将对PyMem_的调用与对平台malloc/realloc/calloc/free的调用混合.例如,在Windows上,不同的DLL最终可能会使用不同的堆,如果使用PyMem_Malloc,您将从Python DLL使用的堆中获取内存; 如果您直接在自己的扩展程序中释放(),那么这可能是一场灾难.使用PyMem_Free可以确保Python可以将内存返回到正确的堆.作为另一个例子,在PYMALLOC_DEBUG模式中,Python将所有对所有PyMem_和PyObject_内存函数的调用包装在特殊的调试包装器中,这些包装器为动态内存块添加了额外的调试信息.系统例程不知道如何处理这些东西,并且Python包装器不知道如何处理由系统例程直接获得的原始块.
然后,里面有一些Python特定的调优,一个函数不仅用于C扩展,而且用于运行Python程序时的所有动态分配,或者:PyMem_MallocPyObject_Malloc100*234str(100)10 + 4j
>>> id(10 + 4j)
139721697591440
>>> id(10 + 4j)
139721697591504
>>> id(10 + 4j)
139721697591440
Run Code Online (Sandbox Code Playgroud)
以前的complex()实例是在专用池上分配的小对象.
小对象(<256字节)分配是非常有效的,因为它是从池8字节对齐的块完成的,每个块大小存在一个池.还有Pages和Arenas块可用于更大的分配.PyMem_MallocPyObject_Malloc
这段关于源代码的评论解释了如何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...
*/
Run Code Online (Sandbox Code Playgroud)
Pools,Pages和Arenas是旨在减少长期运行的Python程序的外部内存碎片的优化.
查看有关Python内存内部的完整详细文档的源代码.