Java 提高JNA性能,而无需重新部署

Java 提高JNA性能,而无需重新部署,java,c,jna,Java,C,Jna,我试图用JNA创建C库与Java代码的绑定,但性能非常差 这是C头文件 struct facet_fin_s { int facet; int fin; }; typedef struct facet_fin_s facet_fin_t; struct tab_facet_fin_s { facet_fin_s *data; int length; }; typedef struct tab_facet_fin_s tab_facet_fin_t; struct facet_s{

我试图用JNA创建C库与Java代码的绑定,但性能非常差

这是C头文件

struct facet_fin_s {
 int facet;
 int fin;
};
typedef struct facet_fin_s facet_fin_t;

struct tab_facet_fin_s {
 facet_fin_s *data;
 int length;
};
typedef struct tab_facet_fin_s tab_facet_fin_t;

struct facet_s{
 int number_of_fins;
 tab_facet_fin_s tab_facet_fin;
};
typedef struct facet_s facet_t;

extern "C" __declspec(dllexport) void getFins(facet_t* const );
这是C文件

void getFins(facet_t* const facet)
{
    facet->number_of_fins = 258246;
    facet->tab_facet_fin.length = facet->number_of_fins;
    facet->tab_facet_fin.data = (facet_fin_s*)malloc(sizeof(facet_fin_s) * facet->tab_facet_fin.length);
    memset(facet->tab_facet_fin.data, 0, sizeof(facet_fin_s) * facet->tab_facet_fin.length);

    int loop = 0;
    for (loop=0; loop<facet->tab_facet_fin.length; loop++)
    {
        facet_fin_s fin;
        fin.facet = loop;
        fin.fin = loop;
        facet->tab_facet_fin.data[loop] = fin;
    }
}
不幸的是,
fins
似乎是
null

编辑2

Technomage告诉我,我必须先阅读
tab\u facet\u fin
。但我仍然无法以数组的形式获得结果

tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
facet_fin_s[] fins = (facet_fin_s[])tab.readField("data");
引发强制转换异常。有没有什么简单的方法来阅读这个领域

编辑3

多亏了Technomage,我在
readField
策略上做了一次完整的尝试。有两种获取数据的方法,这取决于
数据
指针
还是
结构

以下是常见部分(每个java类在其构造函数中调用
setAutoSync(false)

然后是
指针
案例

int length = (int)retFacet.readField("number_of_fins");
tab_facet_fin_s tab = (tab_facet_fin_s)retFacet.readField("tab_facet_fin");
int[] data = new int[length*2];
tab.data.read(0, data, 0, data.length);
for (int i = 0; i < data.length; i++)
{
   System.out.println(data[i]);
}
现在我的意见是:

  • readField
    策略可能是优化性能和避免无用复制的好方法。这可能是一个很好的技巧,但与此无关,因为我的结构只有我想要读取的数据。如果我的项目中的其他结构包含我不想读取的数据,那么我将最终使用它

  • 指针的情况:不幸的是,Jnavior会自动生成我的
    数据
    作为
    结构。通过引用
    而不是
    指针
    。但让我们想象一下,我得到了这些
    指针。然后,我还可以非常快速地访问数据中的int值。如果我没有错的话,这种方法与调用
    指针.getIntArray
    完全相同。我发现这里有两个问题。首先,我完全失去了在Java中使用
    facet\u fin\s
    类的好处。解析数据的方法还可以,但并不十分方便。其次,如果我的结构
    facet\u fin\u s
    拥有其他类型的成员(这是我试图绑定的库的某些结构的情况),那么这个策略是不相关的

  • Structure.ByReference案例:这里的优点是我们将数据作为
    facet\u fin\s
    的数组来获取。这对于代码的可读性来说是一个很好的观点。不幸的是,我们回到了第一个问题,因为我们必须在这里使用这个该死的
    结构。toArray
    来访问数据。此函数用于创建从本机内存到Java内存的内存副本。对于大数据量,此功能非常慢

真的有什么方法可以在不完全重写Java或C代码的情况下快速读取本机内存数据并保持原始的“体系结构”吗

  • 继续使用表示C结构的java类
  • 尽可能避免在Java或C中重写大量工具或类,以便我们只能使用JNAvior
  • 对本机内存的快速可读访问,或从本机内存到java内存的快速复制

我想我正面临JNA的限制…

您应该关闭结构内存的自动同步()。然后,您只能在需要时调用以访问感兴趣的字段

Structure.toArray()
本身不会消耗那么多时间,但是将大量结构的本机内存同步到Java字段最终会导致大量反射,这通常是很慢的。这将取决于涉及的结构数量和每个结构中的字段数量(递归嵌套的结构引用会增加更多开销)

顺便说一句,您可以将
Structure.toArray()
的结果直接强制转换到
facet\u fin\s[]
,这样以后就不必重复强制转换了

如果在许多结构中只有几个字段,并且需要访问所有字段,那么最好使用具有更好Java到本机传输性能的内存块表示(NIO或基元数组)。您真的不想单独传输数千个字段,不管平台是什么。理想情况下,您希望将要传输的所有数据拉入单个缓冲区或数组,并执行一次传输(
Pointer.getIntArray()
可能适用于这种特殊情况)

编辑

假设
选项卡面\u fin
中的
数据
字段的类型为
指针
,则可以按如下方式提取数据:

int[] buf = new int[LENGTH*2];
tab_facet_fin.data.read(0, buf, 0, buf.length);
interface MyLibrary2 extends MyLibrary {
    void myFunction(MyStructure arg);
}
相反,如果将
数据映射为
结构。通过引用
(即
结构*
),则需要执行以下操作:

facet_fin_s s = (facet_fin_s)tab.readField("data");
facet_fin_s[] data = (facet_fin_s[])s.toArray(LENGTH);
interface MyLibrary extends Library {
    void myFunction(Pointer arg);
}
请注意,您应该在要避免自动同步的所有结构的ctor中设置auto sync false,以便在创建结构时自动进行自动同步
Structure.toArray()
在返回之前对所有数组元素调用
Structure.autoRead()

编辑2

一般来说,JVM对任何类型的本机访问都不友好;进行单个本机函数调用会有很大的开销。
Structure.toArray()
的实际开销是逐个读取每个字段,每次读取都会导致JNI交叉。最好的解决方案是尽可能少地进行JNI转换,因此这意味着传输数据,然后将其排序到其组件中

如果您将所有内容都放在一个缓冲区中,那么仍然可以使用JNA计算的信息来访问它。可以想象,您可以创建自己的
Memory
类,该类由本机内存支持,但经过优化,可以一次性读取整个本机内存块,然后覆盖所有
指针.getXXX
方法,以访问Java端缓冲区而不是本机内存。这可能是JNA中一个有用的特性,可以想象是默认的优化。缺点是现在的内存使用率是原来的两倍,所以它不一定总是最好的解决方案

注意:扩展jnavior生成的接口以添加它没有配置的映射是很简单的
int[] buf = new int[LENGTH*2];
tab_facet_fin.data.read(0, buf, 0, buf.length);
facet_fin_s s = (facet_fin_s)tab.readField("data");
facet_fin_s[] data = (facet_fin_s[])s.toArray(LENGTH);
interface MyLibrary extends Library {
    void myFunction(Pointer arg);
}
interface MyLibrary2 extends MyLibrary {
    void myFunction(MyStructure arg);
}