我正在阅读documentation for Memory Management in Python C extensions,据我所知,似乎没有太多理由使用malloc
而不是PyMem_Malloc
。假设我想分配一个不会暴露给Python源代码的数组,并将存储在一个将被垃圾收集的对象中。有没有理由使用malloc
?是否有任何理由通过PyMem_Malloc使用malloc?
回答
编辑:混合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使用的堆中获取内存 ;它可能是一个灾难,如果你直接在你自己的 扩展名中免费()。使用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()
实例是在专用池上分配的小对象。因为它是从池中完成对准块8个字节,现有的对于每个块大小为一个池
PyMem_Malloc
PyObject_Malloc
小物件(< 256字节)分配是相当有效的。还有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...
*/
池,Pages和阿里纳斯都是为了降低长期运行的Python程序的external memory fragmentation优化。
查看the source code了解关于Python内存内部的完整详细文档。
从我写MATLAB MATLAB函数的经验来看,我认为使用malloc或不使用malloc的最大决定因素是可移植性。假设你有一个头文件,它只使用内部的c数据类型来执行一些有用的函数(没有必要的Python对象交互,所以使用malloc没有问题),并且你突然意识到你想要将该头文件移植到不同的代码库与Python无关(也许这是一个纯粹用C编写的项目),使用malloc显然是一个更便携的解决方案。
但是对于纯粹是Python扩展的代码,我最初的反应是希望本机c函数的执行速度更快。我没有证据可以支持:)
扩展使用malloc或其他系统分配器分配内存是完全可以的。对于许多类型的模块来说,这是正常的和不可避免的 - 大多数包装其他库的模块(它们本身对Python一无所知)会在库中发生本地分配。 (有些库允许您控制分配,以防止出现这种情况;大多数情况下不会)。
使用PyMem_Malloc存在一个严重缺陷:您需要在使用GIL时保留GIL。本地库通常希望在执行CPU密集型计算或进行任何可能阻塞的调用(如I/O)时释放GIL。在分配之前需要锁定GIL可能会非常不方便和性能问题之间。
使用Python的包装进行内存分配可以使用Python的内存调试代码。但是,像Valgrind这样的工具,我怀疑它的实际价值。
如果API需要它,您将需要使用这些函数;例如,如果API传递了一个必须用这些函数分配的指针,所以它可以与它们一起被释放。除了使用它们这样的明确理由之外,我坚持正常分配。
- 1. 是否有任何理由通过fgets + sscanf使用scanf或fscanf
- 2. 是否有任何理由使用[:over @:?
- 3. 是否有任何理由使用isset()?
- 4. 是否有任何理由使用System.Uri?
- 5. 当有一个通用的Dictionary类时,是否有任何理由使用Hashtables?
- 6. 是否有任何理由Object.freeze函数?
- 7. C++:是否有任何理由使用uint64_t,而不是size_t
- 8. 是否有任何理由使用SGML而不是XML?
- 9. 是否有任何理由使用Apache HashCodeBuilder而不是Objects.hash?
- 10. 是否有任何理由在C#中使用私有属性?
- 11. 是否有任何理由不使用INLINABLE pragma作为函数?
- 12. 程序员是否有任何理由使用System.in.read()中的char?
- 13. 是否有任何理由使用RabbitMQ而非Kafka?
- 14. 是否有任何理由不使用Boost :: shared_ptrs?
- 15. 是否有任何理由在JavaScript中使用Object.create()或new?
- 16. 是否有任何理由在Android中使用support.v4库?
- 17. 是否有任何理由在vb6中使用DHTML或IIS?
- 18. 是否有任何理由对群集使用锁文件?
- 19. 是否有任何理由使用self关键字?
- 20. 是否有任何理由在'.class'上使用selector'* .class'?
- 21. 是否有任何理由使用jpg文件扩展名?
- 22. 是否有任何理由不使用resource.getInputStream()?
- 23. 是否有任何理由在VBA中使用ENUM?
- 24. 是否有任何理由使用threading.Lock over multiprocessing.Lock?
- 25. 是否有任何理由在Swift中使用选择器?
- 26. 是否有任何理由避免使用bigint代替主键?
- 27. 是否有任何理由在java中使用null == value条件?
- 28. 是否有任何理由使用等待和异步马上?
- 29. 是否有任何理由在两个MemoryStream之间使用CopyToAsync
- 30. 是否有任何理由,你为什么会使用document.writeln
对于期望本机C函数执行得更好,您是正确的。问题是它们都是本地C函数。 :-) – 2011-01-27 23:59:11
嗯,我想他们是......很好的技术性:)我想我的意思是说,我希望C的本地内存分配系统比为Python的内存分配系统实现的本地C更快:P – William 2011-01-28 00:22:41