gpt4 book ai didi

java - Java JNA:应用程序完成后JRE崩溃

转载 作者:行者123 更新时间:2023-12-01 09:49:42 24 4
gpt4 key购买 nike

我正在使用JNA访问本机库。这是我第一次使用JNA,而且我也没有使用c / c ++的经验。我能够使该应用程序正常工作,并且使用System.out.println()返回并显示了正确的结果。这是我代码的最后一行。该值显示在控制台中,然后Java崩溃,例如。将显示对话框Java Platform SE binary has stopped working,其中包含关闭或调试选项。

然后,控制台将显示以下内容:

Java Result: -1073741819

Windows事件查看器说0xc0000005根据现有答案是我

编辑5 2018年8月21日:

这仍然没有解决,现在我再次进行调查。解决的是循环时MemoryError的问题。由于我现在确实需要解决方案,因此我也不再混淆dll。 AFAIK供应商将其停业。他们不回答问题,该网站已过时。

我的“文档”来自here

这里是当前的java代码:

public interface CLogP extends StdCallLibrary {
CLogP INSTANCE = (CLogP) Native.loadLibrary("BB-CLOGP", CLogP.class);
NativeLong calcLogP(String smiles, FloatByReference logP, NativeLongByReference numContrb, HANDLEByReference contrib);
}

public static void main(String[] args) {

//contrib can also be a PointerByReference, the behaviour is the same
HANDLEByReference contrib = new HANDLEByReference();
FloatByReference cLogP = new FloatByReference();
NativeLongByReference numContrib = new NativeLongByReference();
NativeLong err = CLogP.INSTANCE.calcLogP("c1ccccc1", cLogP, numContrib, contrib);
System.out.println(err.intValue());
System.out.println(cLogP.getValue());
System.out.println(numContrib.getValue());
//needs to be done after ever call to calcLogP
//then no issue running in a loop
Kernel32.INSTANCE.GlobalFree(contrib.getValue().getPointer());
// Tried to free other variables, does not have any effect
//Kernel32.INSTANCE.GlobalFree(cLogP.getPointer());
//Kernel32.INSTANCE.GlobalFree(numContrib.getPointer());
}


我有点迷路了。以上适用于dll的过时版本,但不适用于最新版本的dll。怎么了拆卸它有任何帮助吗?

旧代码和信息,现在仅部分相关:

我的代码:

public static void main(String[] args) {

FloatByReference result = new FloatByReference();
//EDIT: changed to NativeLongByReference as per suggested answer
NativeLongByReference numContrib = new NativeLongByReference();
// This is a struct that needs to be passed by reference
MyDll.PContribution.ByReference contrib = new MyDll.PContribution.ByReference();
NativeLong err = MyDll.INSTANCE.calcResult("myValue", result, numContrib, contrib);
// I only care about result and not the other out-parameters
System.out.println(result.getValue());
//crash here
}


在c中定义函数:

typedef long (CALCRESULT)(const char*, float*, long*, HANDLE*);

怎么了?我需要在应用程序终止之前执行一些清理吗?

编辑:

我可以循环运行方法调用,并且可以正常工作。它只有在终止时才崩溃。

编辑2:

根据这里的注释MyDll代码:

public interface MyDll extends Library {

public static class PContribution extends Structure {
public static class ByReference extends PContribution implements Structure.ByReference {

public byte[] Class = new byte[10];
public byte[] Type = new byte[6];
public byte[] Description = new byte[40];
public byte[] Comment = new byte[10];
public float Value;
}
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "Class", "Type", "Description", "Comment", "Value" });
}
}

MyDll INSTANCE = (MyDll) Native.loadLibrary("MyDll", MyDll.class);

NativeLong calcResult(String smi, FloatByReference result, NativeLongByReference numContrb, PContribution contrib);
}


struct的定义:

typedef struct {
char Class[10];
char Type[6];
char Description[40];
char Comment[10];
float Value;
} PContribution;


编辑3:

该死的。我发现可用的文档适用于dll的旧版本。使用旧的dll,一切正常。因此,现在我需要从供应商处获取新版本的文档。

编辑4:

它适用于旧的dll,但该应用在65533次迭代(调用)后始终崩溃。每个调用使用完全相同的参数。

java.lang.Error: Invalid memory access

at com.sun.jna.Native.invokeInt(Native Method)
at com.sun.jna.Function.invoke(Function.java:390)
at com.sun.jna.Function.invoke(Function.java:323)
at com.sun.jna.Library$Handler.invoke(Library.java:236)
at com.sun.proxy.$Proxy0.calcLogP(Unknown Source)


练习的重点是能够快速拨打数千个电话。

最佳答案

您得到的Java结果是一条错误消息。 -1073741819是0xc0000005,这是STATUS_ACCESS_VIOLATION的代码:您正在访问没有权限的内存。

它在应用程序关闭时发生的事实表明它与对象终结相关联,后者在程序终止时发生,也可能在触发垃圾回收时发生。 Java / JNA可能试图释放C尚未分配的内存。

当您遇到这种错误时,您应该调查:


从C到JNA的类型映射(尤其是对象大小)
内存分配与Java与C不匹配(哪一侧正在分配内存)
释放由API在C端分配的资源/内存(句柄,引用,端口等)


类型映射

代码与c函数定义的比较显示出两个不匹配的地方。


CALCRESULT函数在C中具有指向long的指针。operating system dependent是32位还是64位长,而Java的long始终是64位。您应该将本机long值映射到JNA的NativeLong类型。尽管在这种情况下这可能不会导致崩溃,但至关重要的是要知道值在数组或结构内部时的区别,因为它会抛出字节偏移。因此,作为指向本机long的指针,变量numContrib的类型应为NativeLongByReference
CALCRESULT函数在C中具有指向HANDLE类型的指针,但是您传递了一个结构(通过引用)。这里有一些注意事项:


我不确定为什么您必须使用ByReference。当您将结构作为这样的参数传递时,JNA会将其变为您的指针,并负责分配和释放内存,并为您自动将本机内存读取到该结构中。因此,通常您不会通过引用传递结构。 (就我个人而言,我喜欢避免使用ByReference结构,而直接操作Pointer,使用该Pointer创建一个新的Structure。可能是同一件事,但对我而言更清楚了发生了什么。)
C方法指定特定Windows类型HANDLE的指针。 Handle是对内部维护表的引用,该表可以访问其他系统资源,等等。在使用完句柄或将其占用后,应释放它们。 JNA对HANDLE类型进行建模;在这种情况下,您有一个指针,因此适当的类型可能是HANDLEByReference



内存分配不匹配

目前尚不清楚,当API向您提供指向HANDLE类型(JNA HANDLEByReference)的指针时,为什么要使用结构。当您定义结构的new实例(在您的情况下为PContribution)时,Java会分配必要的内存,并且JNA会为您将Java内存映射到本地内存。但是,C函数提供了指向HANDLE类型的指针,该类型占用的内存少于您定义的结构。当Java在Java端释放结构内存,然后尝试在C端释放相同的内存时,这完全有可能会出现问题,因为它告诉C释放比结构C分配的更多的内存(用于结构)(的句柄)。如果没有来自API的更清晰的文档说明如何从该HANDLE到已在其位置列出的结构,则无法进一步回答此问题。

释放资源

由于API使用的是HANDLE类型,因此可能涉及内存以外的其他资源,并且您有责任释放这些引用。请参见CloseHandle()函数。您是否必须使用此函数自己关闭该句柄,或者API是否使用自己的实现CloseHandle() internal的方法之一为您关闭它(在这种情况下,对于CALCRESULT函数)。没有API进行检查,我无济于事,但请仔细阅读文档,以了解是否需要显式释放/释放在代码中创建的任何结构,以及如何进行释放。

关于java - Java JNA:应用程序完成后JRE崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37678424/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com