【发布时间】:2019-04-19 18:20:56
【问题描述】:
我有一个问题,在我创建指向它们的指针后,我无法在 Python 中正确关闭 mmap-s。我的用例是我打开文件(通常是用于硬件的 UIO 设备,但问题也发生在普通文件上),对它们进行内存映射,然后将它们用作 ctypes 结构的缓冲区。通常是数据结构或数组。一个最小的示例如下所示:
import ctypes as ct
import mmap
import os
fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map)
# Use the memory object to do things here
del memory
map.close()
os.close(fileno)
那时一切都很好。
但是,有时我需要调用一些也需要访问该内存的 C 库函数,因此我必须传入指向它们的指针。我使用以下方法创建该指针:
ptr = ct.cast(memory, ct.c_void_p)
除了一件事之外,所有这些都非常有效。一旦我创建了这样一个指针,我就无法再关闭内存映射。以这个稍微扩展的例子为例:
import ctypes as ct
import mmap
import os
fileno = os.open('/tmp/testfile', os.O_RDWR | os.O_SYNC)
map = mmap.mmap(fileno, 32768, flags=mmap.MAP_SHARED)
memory = (ct.c_uint32 * 8192).from_buffer(map)
# Use the memory object to do things here
ptr = ct.cast(memory, ct.c_void_p)
del ptr
del memory
map.close()
os.close(fileno)
运行此程序会导致以下异常:
Traceback (most recent call last):
File "pointer_test.py", line 14, in <module>
map.close()
BufferError: cannot close exported pointers exist
Process finished with exit code 1
我对引用map-instance 的内容进行了一些分析(使用gc.get_referrers),结果发现memoryview-instance 仍然存在。最后,这回溯到 ctypes 数组:
[<__main__.c_uint_Array_8192 object at 0x7f954bd1e0>,
[{547965620704: <__main__.c_uint_Array_8192 object at 0x7f954bd1e0>,
'ffffffff': <memory at 0x7f95621a08>},
[<memory at 0x7f95621a08>,
[<managedbuffer object at 0x7f95746d08>,
但是,这并没有真正帮助我。我想知道如何摆脱那个指针。我知道这可能并不完全安全,因为我当然可以在某处始终拥有该指针的副本。但是在创建指针后完全防止关闭mmap 似乎也不是一个好主意。任何人都知道如何让 Python 相信我丢弃了所有指针,现在可以安全地关闭 mmap?
【问题讨论】:
-
和你做了同样的测试,得到了同样的结果。我认为这只是 python 在某处保存的一个 ref,所以我就这样做了:
import gc和gc.collect()并尝试在此之后立即关闭 mem 映射文件:它起作用了......我看不到任何其他方式告诉 python mem map 上没有 refs :(
标签: python pointers ctypes mmap memoryview