You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python ctypes复制临时缓冲区中结构体失败问题求助

使用ctypes调用黑箱动态链接库时的内存复制问题

我在使用Python的ctypes调用黑箱动态链接库some_library时遇到内存管理问题:调用库接口分配内存、读取数据、解码并获取结构体引用后,释放内存会导致返回的结构体引用失效;但如果不释放内存则会造成内存泄漏,必须在函数返回前完成内存释放。尝试复制结构体后,数据仍然不正确,释放内存后复制的结构体也跟着失效。

原代码

from ctypes import *
some_library = CDLL('/usr/lib/black_box.so')

# This `Group` comes from `some_library`
class Group(Structure):
    _fields_ = [
        ("ChSize", c_uint32*9),
        ("DataChannel", POINTER(c_float)*9),
        ("TriggerTimeLag", c_uint32),
        ("StartIndexCell", c_uint16)]

class Thing(Structure):
    _fields_ = [
        ("A", c_uint8*4),
        ("B", Group*4)]

pointer_to_thing = POINTER(Thing)()

def get_things():
    some_library.allocate_memory()
    some_library.read_things()
    things = []
    for n in range(some_library.how_many_things_did_your_read()):
        some_library.decode_next_thing()
        pointer_to_thing = some_library.give_me_the_thing()
        thing = pointer_to_thing.contents
        things.append(thing)
    some_library.release_memory()
    return things

things = get_things()

这段代码运行失败,因为some_library.give_me_the_thing()返回的是Thing结构体的引用,some_library.release_memory()会释放该结构体所在的内存,导致返回列表中的对象失效。注释release_memory()可正常运行,但必须在函数返回前释放内存。

尝试的复制方法

方法1:使用memmove复制

def get_things():
    some_library.allocate_memory()
    some_library.read_things()
    things = []
    for n in range(some_library.how_many_things_did_your_read()):
        some_library.decode_next_thing()
        pointer_to_thing = some_library.give_me_the_thing()
        thing = pointer_to_thing.contents
        copy_of_thing = Thing()
        memmove(
            addressof(copy_of_thing),
            addressof(thing),
            sizeof(Thing),
        )
        things.append(copy_of_thing)
    some_library.release_memory()
    return things

返回的Thing数据始终不正确,注释release_memory()则正常。

方法2:使用copy_from_buffer复制

def get_things():
    some_library.allocate_memory()
    some_library.read_things()
    things = []
    for n in range(some_library.how_many_things_did_your_read()):
        some_library.decode_next_thing()
        pointer_to_thing = some_library.give_me_the_thing()
        thing = pointer_to_thing.contents
        copy_of_thing = Thing.copy_from_buffer(thing)
        things.append(copy_of_thing)
    some_library.release_memory()
    return things

结果与方法1完全相同。

观察到的现象

插入打印语句输出对象地址:

<Thing object at 0x7f8d6f027840> original
<Thing object at 0x7f8d6f0278c0> copy
--------
<Thing object at 0x7f8d6f027940> original
<Thing object at 0x7f8d6f027840> copy
--------
<Thing object at 0x7f8d6f0279c0> original
<Thing object at 0x7f8d6f027940> copy
--------

可见复制的对象地址复用了原对象的地址,推测复制的内存仍由some_library管理,释放后复制的结构体也被销毁。由于some_library是复杂黑箱,无法提供最小可复现示例,寻求解决方法。


内容的提问来源于stack exchange,提问作者user171780

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 12:04:54