我正在使用JNA访问本机库。这是我第一次使用JNA,我也没有使用c/c++的经验。我能够使应用程序正常工作,并获得了使用System.out.println()返回和显示的正确结果。这是我代码的最后一行。该值显示在控制台中,然后Java崩溃,例如。显示对话框Java Platform SE binary has stopped working时,可以选择关闭或调试。
控制台随后显示如下:
Java Result: -1073741819
Windows事件查看器显示0xc0000005,根据现有答案,这是一个me。
编辑5 2018年8月21日:
这件事还没有解决,现在我又开始调查了。解决的是MemoryError循环时的问题。因为我现在真的需要一个解决方案,所以我也不再混淆dll。AFAIK的供应商,它的停业。他们不回答问题,网站已经过时了。
我的“文档”来自这里
下面是当前的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版本,但与最新的一个。出什么问题了?拆开它会有什么帮助吗?
旧代码和信息,现在只部分相关:
我的代码:
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*);
出什么问题了?在应用程序终止之前,我需要执行一些清理吗?
编辑:
我可以在循环中运行这个方法调用,它可以工作。只有当它终止时它才会崩溃。
EDIT2:
根据这里的注释,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) 整个练习的目的是能够快速地打上千个电话。
发布于 2016-06-07 17:01:29
您得到的Java结果是一条错误消息。-1073741819是0xc0000005,这是STATUS_ACCESS_VIOLATION的代码:您正在访问没有权限的内存。
它是在应用程序关闭时发生的,这表明它与对象终结相关联,这是在程序终止时发生的,在触发垃圾回收时也可能发生。Java/JNA很可能正在尝试释放C没有分配的内存。
当您得到这样的错误时,您应该调查:
型映射
代码与c函数定义的比较显示了两种不匹配。
long的指针,无论这是32位还是64位长都是操作系统依赖,而Java的long总是64位。您应该将本机long值映射到JNA的NativeLong类型。虽然在这种情况下,这可能不会导致崩溃,但当值位于数组或结构中时,了解这种区别非常重要,因为它会抛出字节偏移量。因此,作为指向本机long的指针,变量numContrib应该是NativeLongByReference类型。HANDLE类型的指针,但是您传递了一个结构(通过引用)。这里有几个注释:- I'm not sure why you have to use ByReference. When you pass a structure as an argument like this, JNA turns it into the pointer for you, and takes care of allocating and releasing memory, and auto-reading the native memory into the structure for you. So in general you wouldn't pass a structure by reference. (Personally, I like to avoid ByReference structures, and just manipulate a `Pointer` directly, creating a new Structure using that Pointer. Probably the same thing but it's more clear to me what's happening.)
- The C method specifies a pointer the specific Windows type `HANDLE`. A [Handle](https://msdn.microsoft.com/en-us/library/windows/desktop/ms724457(v=vs.85%29.aspx) is a reference to an internally maintained table that has access to other system resources, etc. Handles should be released when you are done using them, or you tie up those resources. JNA models the `HANDLE` type; in this case you have a pointer so the appropriate type would probably be a [HANDLEByReference](http://java-native-access.github.io/jna/4.2.0/com/sun/jna/platform/win32/WinNT.HANDLEByReference.html).
内存分配不匹配
当API为您提供指向HANDLE类型(JNA HANDLEByReference)的指针时,不清楚为什么要使用结构。Java在定义结构的new实例(在您的例子中是PContribution)时分配必要的内存,JNA将为您将该Java内存映射到本地内存。但是,C函数给出了一个指向HANDLE类型的指针,它占用的内存比您定义的结构少。当Java释放Java端的结构内存,然后试图在C端释放相同的内存时,完全有可能遇到问题,因为它告诉C释放更多的内存(用于结构)而不是C分配的内存(用于句柄)。如果没有API中关于如何从这个句柄到它所列出的结构的更清楚的文档,就不可能进一步回答这个问题。
发布资源
由于API使用的是HANDLE类型,所以可能涉及到内存以外的其他资源,因此您有责任发布这些引用。请参阅CloseHandle()函数。无论您是否必须用这个函数自己关闭句柄,或者API是否会用它自己的实现CloseHandle()内部所有的方法来关闭它,都应该在API中清楚地记录下来(在本例中是CALCRESULT函数)。如果没有API来检查,我将无能为力,但请仔细阅读文档,看看您在代码中创建的任何结构是否需要显式地释放/释放,以及如何释放。
https://stackoverflow.com/questions/37678424
复制相似问题