【发布时间】:2014-02-22 21:26:20
【问题描述】:
我正在编写一个 Python 模块来在 O_DIRECT 上下文中执行 IO。 O_DIRECT 的限制之一是,对于 2.4 和 2.5 内核,您必须读入在 4096 字节边界上对齐的缓冲区,而 2.6 及更高版本将接受 512 的任何倍数。
明显的内存分配候选者是posix_memalign(void **memptr, size_t alignment, size_t size)
在我的代码中,我这样分配一个区域:
char *buffer = NULL;
int mem_ret = posix_memalign((void**)&buffer, alignment, size);
if (!buffer) {
PyErr_NoMemory();
return NULL;
}
/* I do some stuff here */
free(buffer);
当我使用 python3.2 编译和导入模块时,这个(以及其他未显示的模块)工作正常。
当我尝试对 python2.7 进行相同操作时(我想保持兼容性),它会抛出 PyErr_NoMemory 异常和mem_ret == ENOMEM,表明它无法分配。
为什么我编译的 Python 版本会影响 posix_memalign 的运行方式?
操作系统:Ubuntu 12.04 LTS
编译器:Clang + GCC 显示相同的行为
更新
感谢 user694733,我现在有了一段工作代码
然而,它的工作原理让我更加困惑:
#if PY_MAJOR_VERSION >= 3
char *buffer = NULL;
int mem_ret = posix_memalign((void**)&buffer, alignment, count);
#else
void *mem = NULL;
int mem_ret = posix_memalign(&mem, alignment, count);
char *buffer = (char*)mem;
#endif
谁能解释为什么 incorrect 第一个块在 Python3 下工作,但不是 2.7,更重要的是为什么 正确 第二个块在 Python3 下不工作?
更新 2
情节变厚了,确定了下面代码的正确形式后,我在 4 个不同版本的 Python 上进行了测试。
void *mem = NULL;
int mem_ret = posix_memalign(&mem, alignment, count);
char *buffer = (char*)mem;
if (!buffer) {
PyErr_NoMemory();
return NULL;
}
/* Do stuff with buffer */
free(buffer);
在 Python 2.7 下:此代码按预期运行。
在 Python 3.1 下:此代码按预期运行。
在 Python 3.2 下:此代码生成 mem_ret == ENOMEM 并为 buffer 返回 NULL
在 Python 3.3 下:此代码按预期运行。
未包含在 Ubuntu 存储库中的 Python 版本是从位于 https://launchpad.net/~fkrull/+archive/deadsnakes 的 PPA 安装的
如果要相信标记为 Python 二进制文件的版本,我安装的版本是:
python2.7
python3.1
python3.2mu (--with-pymalloc --with-wide-unicode)
python3.3m (--with-pymalloc)
在默认 Python3 发行版中使用宽 unicode 标志会导致此错误吗?如果是这样,这是怎么回事?
为了清楚起见,ENOMEM 分配失败将出现在malloc() 的任何变体中,即使是像malloc(512) 这样简单的变体。
【问题讨论】:
-
请注意,将
char**转换为void**无效。指针可能有不同的大小。使用void *buffer = NULL;,以后如果需要字节访问可以分配给char*。 -
您是否尝试过打印
size和alignment看看它们是否有意义?也许它们被更改为代码其他地方某些 UB 的副作用。 -
即使我硬编码这些参数并调用文字 posix_memalign(buffer, 512, 512) 它仍然无法在 2.7 下分配
-
Python 3.3 始终是 AFAIK 构建的,就好像您已经定义了
--with-wide-unicode。 -
@filmor 如果我们查看古代历史是:docs.python.org/2.3/whatsnew/section-pymalloc.html 特别是
In 2.3, pymalloc has had further enhancements and is now enabled by default这表明 PyMalloc 应该内置到 2.7 和 3.1 中,但它们缺少m标签,这是不一致的还是那些没有它的版本是真正构建的?我机器上的 2.7 是 Ubuntu LTS 附带的版本。
标签: python c memory-management cpython