Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JNA:释放本机内存后存储Java字符串的副本_Java_Jna - Fatal编程技术网

JNA:释放本机内存后存储Java字符串的副本

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)用于填充某些实例。然后我会这样使

我有一个本机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)
用于填充某些实例。然后我会这样使用:

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); }
}