Python 调整(收缩)ctypes数组的大小
假设我有一个10元素的数组:Python 调整(收缩)ctypes数组的大小,python,arrays,resize,ctypes,Python,Arrays,Resize,Ctypes,假设我有一个10元素的数组: from ctypes import * arr = c_float * 10 ,我想把它缩小到5个元素。我试过这样做: resize(arr, sizeof(c_float) * 5) arr = (c_float * 5).from_address(addressof(arr)) 但是我得到了一个ValueError:最小大小是XXX异常,这意味着我不能收缩内存,只能增加内存。如果我真的想,有没有可能用一个聪明的黑客来克服这个限制?这似乎很好: >&g
from ctypes import *
arr = c_float * 10
,我想把它缩小到5个元素。我试过这样做:
resize(arr, sizeof(c_float) * 5)
arr = (c_float * 5).from_address(addressof(arr))
但是我得到了一个
ValueError:最小大小是XXX
异常,这意味着我不能收缩内存,只能增加内存。如果我真的想,有没有可能用一个聪明的黑客来克服这个限制?这似乎很好:
>>> float_10 = c_float * 10
>>> float_5 = c_float * 5
>>> a1 = float_10(range(10))
>>> a2 = float_5.from_address(addressof(a1))
>>> print list(a1)
[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
>>> print list(a2)
[0.0, 1.0, 2.0, 3.0, 4.0]
编辑:这实际上不会调整原始列表的大小,而且
addressof(a1)
将等于addressof(a2)
,因此列表中未使用的位将保留在内存中…本机C函数realloc
允许内存收缩。这可能不安全,但实际上会在调整阵列大小后释放内存:
from ctpyes import *
clib = CDLL("libc.so.6")
bigarr = (c_float * 10)(*range(10)) # some data
smallarr = (c_float * 5).from_buffer(bigarr) # no copies here
# free unneeded memory
clib.realloc(bigarr, sizeof(smallarr))
# finally, delete the bigarr python object because occasional
# use of its truncated elements may cause segfault.
del bigarr
我用100000浮点数组测试了它,看看内存是否真的被释放了
UPD:正如AKX所指出的(这里也包括:),这种方法不能保证
realloc
的返回将指向与以前使用的原始数组相同的内存位置,尽管在我的实践中总是这样 这就是我现在所拥有的,我保存了实际大小
,并且只在增长时调整大小。是的,我认为没有任何安全的方法可以在不复制数据的情况下缩小数组…@GiovanniFunchal,这难道不能回答您的问题吗?您不是应该查看realloc
的返回值,看看它在调整缓冲区大小时是否移动了缓冲区吗?此外,我想Python甚至不能保证使用libc内存分配器(可以使用jemalloc或其他什么),因此realloc
可能会对缓冲区造成绝对的破坏。。。耸耸肩:)@AKX,我对此进行了多次测试,realloc
始终返回与bigarr和smallarr的addressof
相同的值。如果无法调整原始数组的大小,它将返回另一个指针。我认为在不移动的情况下缩小数组应该是可行的,因为不需要更多的内存。是的,但是realloc
的规范说它将返回新的位置,所以允许它这样做。@AKX,你是对的。出于好奇,您是否知道clib.realloc
会在收缩时移动数据?