JNA:释放本机内存后存储Java字符串的副本
我有一个本机C结构,其中包含指向字符串的指针:JNA:释放本机内存后存储Java字符串的副本,java,jna,Java,Jna,我有一个本机C结构,其中包含指向字符串的指针: struct mystruct { char *name; } 以及为名称分配内存的本机函数: void fill(struct mystruct *s, int count) { for (int i = 0; i < count; i++) s[i].name = strdup("something"); } 和void fill(MyStruct[]structs,int count)用于填充某些实例。然后我会这样使
struct mystruct {
char *name;
}
以及为名称分配内存的本机函数:
void fill(struct mystruct *s, int count) {
for (int i = 0; i < count; i++)
s[i].name = strdup("something");
}
和void fill(MyStruct[]structs,int count)
用于填充某些实例。然后我会这样使用:
MyStruct[] structs = new MyStruct[10];
fill(structs, structs.length);
完成后,必须调用一个清理例程void-free(MyStruct[]structs)
,它清理整个数组(由strdup分配的所有内存)。没有一种方法可以逐个实例对结构实例进行清理
我面临的问题是,释放数组后,Java字符串已损坏。如何为每个MyStruct实例创建一个副本,以便释放本机内存,只处理使用纯Java字符串的MyStruct实例?尽管MyStruct没有实现
Cloneable
接口,但它有一个继承自Java.lang.Object
的clone()
方法。因此我相信,您可以覆盖clone()
,而不会干扰JNA
class MyStruct {
String name;
@Override
protected Object clone() throws CloneNotSupportedException {
MyStruct myStruct = new MyStruct();
myStruct.name = new String(this.name);
return myStruct;
}
}
现在可以迭代structs
并克隆每个元素。
如果由于扩展了结构
,所以这不起作用,您可以更改上述方法,从而实例化一个不同的(非本机)类
class MyStruct {
String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return new NonNativeStruct(new String(name));
}
}
class NonNativeStruct {
private String name;
public NonNativeStruct(String name) {
this.name = name;
}
}
请注意,这样做违反了契约
x.clone().getClass()==x.getClass()
。一旦释放了支持结构的本机内存,就不应该再引用Java对象,或者应该创建一个具有自己内存支持的新对象
如果需要手动管理内存,请不要将字段映射到字符串
,而是使用指针
,例如
class MyStruct extends Structure {
public Pointer name;
public String getName() { return name == null ? null : name.getString(0); }
}
一般来说,只要不调用Structure.read()
或Structure.write()
(请注意,JNA在本机函数调用之前和之后自动调用这些方法),那么在释放本机内存备份后使用JNA结构不会直接受到影响。然而,如果你选择这样做,确保你知道你在做什么;有更安全的方法来开发代码。在释放结构名称
字段后,将其设置为NULL
。否则JNA会假设它是一个有效指针并尝试从中读取。我还建议将name
字段设置为固定宽度数组,这样就可以避免分配和释放额外内存的问题。YMMV.我需要释放本机内存,但要传递一个结构副本(使用实际字符串值)。虽然我确实尝试了创建字符串的cpy,就像您创建的新字符串(旧结构名)
一样,但我仍然看到了损坏的字符串。也许我的测试不好..你在使用免费<代码>之前复制了吗?是的,读/写同步是我用来解决问题的方法。目前这只是权宜之计。
class MyStruct extends Structure {
public Pointer name;
public String getName() { return name == null ? null : name.getString(0); }
}