简体   繁体   English

有没有办法在 JNA 中记录无效内存访问的原因

[英]Is there a way to log the reason of an Invalid memory access in JNA

I have the following error when invoking Java code from C using JNA:使用 JNA 从 C 调用 Java 代码时出现以下错误:

Native Exception in org.InvokerPackageCallback@3ba987b8
java.lang.Error: Invalid memory access
  at com.sun.jna.Native.getStringBytes(Native Method)
  at com.sun.jna.Native.getString(Native.java:2248)
  at com.sun.jna.Pointer.getString(Pointer.java:681)
  at com.sun.jna.Structure.readField(Structure.java:743)
  at com.sun.jna.Structure.read(Structure.java:605)
  at org.PackageStruct$ByReference.read(PackageStruct.java:102)
  at com.sun.jna.Structure.autoRead(Structure.java:2234)
  at com.sun.jna.Structure.conditionalAutoRead(Structure.java:576)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.convertArgument(CallbackReference.java:650)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.invokeCallback(CallbackReference.java:571)
  at com.sun.jna.CallbackReference$DefaultCallbackProxy.callback(CallbackReference.java:610)
  at com.sun.jna.Native.invokeVoid(Native Method)
  at com.sun.jna.Function.invoke(Function.java:415)
  at com.sun.jna.Function.invoke(Function.java:361)
  at com.sun.jna.Library$Handler.invoke(Library.java:265)

In my use case the C code invoke the publish_package_fct_pt function which is mapped to a Java interface method.在我的用例中,C 代码调用了映射到 Java 接口方法的publish_package_fct_pt函数。 This method has only one structure argument:此方法只有一个结构参数:

void publish_package_fct_ptr(void (*pf) (PackageStruct));

I use the following library:我使用以下库:

public interface MyLib extends Library {
   public void publish_package_fct_ptr(InvokerPackage callback);

   public interface InvokerPackage extends Callback {
      void invoke(PackageStruct.ByReference pack);
   }
}

with the following structure definition:具有以下结构定义:

public class PackageStruct extends Structure {
  public NativeLong id;
  public int type;
  public int subtype;   
  public String configuration;   
  public String name;
  public NativeLong date;

  public PackageStruct(Pointer peer) {
    super(peer);
  }

 public PackageStruct() {
   super();
 }

 protected List<String> getFieldOrder() {
    return Arrays.asList("id", "type", "subtype", "configuration", "name", "date");
 }

 public static class ByReference extends PackageStruct implements Structure.ByReference {
  public void read() {
     super.read();
  }
}

The C structure is: C结构是:

struct PackageStruct {
  long id;
  int type;
  int subtype;
  const char *configuration;
  const char *name;
  long date;
};

It worked correctly before I added the configuration field, and I have the exception now.在我添加configuration字段之前它工作正常,现在我有例外。 I "think" that the configuration field points to nothing, which might be the reason why I have this error.我“认为” configuration字段没有指向,这可能是我出现此错误的原因。

Do you agree with my hypothesis?你同意我的假设吗? And is there a mean in JNA to log the com.sun.jna.Structure.readField to know for which field I have this error?在 JNA 中是否有一种方法可以记录com.sun.jna.Structure.readField以了解我遇到此错误的哪个字段?

The "Invalid Memory Access" error thrown by JNA is a graceful"handling of native memory errors caught by Structured Exception Handling . So to answer the question in the title, unfortunately you can't get more details from the native side. JNA 抛出的“无效内存访问”错误是对Structured Exception Handling捕获的本机内存错误的优雅“处理”。因此,要回答标题中的问题,不幸的是您无法从本机方面获得更多详细信息。

All you really need to know is that either You are attempting to access native memory that you do not own or Your native memory allocation failed .您真正需要知道的是,您正在尝试访问不属于您的本机内存,或者您的本机内存分配失败

Your mappings look correct, but you haven't shown the code where you actually call the publish_package_fct_ptr() method.您的映射看起来正确,但您没有显示实际调用publish_package_fct_ptr()方法的代码。 That's where the problem probably exists.这就是问题可能存在的地方。 However, the fact that it's a callback points to a very common problem with JNA and callbacks, in which the memory is released before you use it so I'll hazard a guess here.然而,它是回调的事实指出了 JNA 和回调的一个非常常见的问题,其中内存在您使用它之前被释放,所以我在这里冒险猜测。

(Aside: you don't need to declare a Structure ByReference if used as a method argument. That's the default. You might also find the @FieldOrder annotation cleaner than the override of the getFieldOrder() method.) (另外:如果用作方法参数,则不需要声明 Structure ByReference。这是默认设置。您可能还会发现@FieldOrder注释比getFieldOrder()方法的覆盖更清晰。)

JNA tracks its memory allocation using the Memory class. JNA 使用Memory类跟踪其内存分配。 If you don't provide the Structure a pointer when you construct it, it will allocate the necessary memory and store that internally in a Memory object.如果在构造它时没有为 Structure 提供指针,它将分配必要的内存并将其内部存储在Memory对象中。 This works for most uses of structures.这适用于结构的大多数用途。

However, releasing the native memory is tied to Java's garbage collection.但是,释放本机内存与 Java 的垃圾收集相关联。 When the Structure is GC'd its internal memory object is also GC'd and as part of its finalize() execution it releases the native memory.当 Structure 被 GC 处理时,它的内部内存对象也被 GC 处理,并且作为finalize()执行的一部分,它会释放本机内存。

If the callback is the last time you reference the Structure in Java, it becomes unreachable and is eligible to be GC'd.如果回调是您最后一次在 Java 中引用该结构,则它变得无法访问并且有资格被 GC 处理。 In some cases, this could happen before the callback finishes executing, taking away that native memory allocation.在某些情况下,这可能会在回调完成执行之前发生,从而取消本机内存分配。

If you are using JDK 9+, using a ReachabilityFence after the callback will solve this problem.如果您使用的是 JDK 9+,则在回调后使用ReachabilityFence将解决此问题。 For JDK 8 and earlier, you may have to do some other code manipulation of the Structure after it's used in the callback, to ensure Java retains a reference to it (and its underlying native memory).对于 JDK 8 及更早版本,在回调中使用 Structure 之后,您可能必须对其进行一些其他代码操作,以确保 Java 保留对其(及其底层本机内存)的引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM