繁体   English   中英

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

[英]Is there a way to log the reason of an Invalid memory access in 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)

在我的用例中,C 代码调用了映射到 Java 接口方法的publish_package_fct_pt函数。 此方法只有一个结构参数:

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

我使用以下库:

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

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

具有以下结构定义:

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

C结构是:

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

在我添加configuration字段之前它工作正常,现在我有例外。 我“认为” configuration字段没有指向,这可能是我出现此错误的原因。

你同意我的假设吗? 在 JNA 中是否有一种方法可以记录com.sun.jna.Structure.readField以了解我遇到此错误的哪个字段?

JNA 抛出的“无效内存访问”错误是对Structured Exception Handling捕获的本机内存错误的优雅“处理”。因此,要回答标题中的问题,不幸的是您无法从本机方面获得更多详细信息。

您真正需要知道的是,您正在尝试访问不属于您的本机内存,或者您的本机内存分配失败

您的映射看起来正确,但您没有显示实际调用publish_package_fct_ptr()方法的代码。 这就是问题可能存在的地方。 然而,它是回调的事实指出了 JNA 和回调的一个非常常见的问题,其中内存在您使用它之前被释放,所以我在这里冒险猜测。

(另外:如果用作方法参数,则不需要声明 Structure ByReference。这是默认设置。您可能还会发现@FieldOrder注释比getFieldOrder()方法的覆盖更清晰。)

JNA 使用Memory类跟踪其内存分配。 如果在构造它时没有为 Structure 提供指针,它将分配必要的内存并将其内部存储在Memory对象中。 这适用于结构的大多数用途。

但是,释放本机内存与 Java 的垃圾收集相关联。 当 Structure 被 GC 处理时,它的内部内存对象也被 GC 处理,并且作为finalize()执行的一部分,它会释放本机内存。

如果回调是您最后一次在 Java 中引用该结构,则它变得无法访问并且有资格被 GC 处理。 在某些情况下,这可能会在回调完成执行之前发生,从而取消本机内存分配。

如果您使用的是 JDK 9+,则在回调后使用ReachabilityFence将解决此问题。 对于 JDK 8 及更早版本,在回调中使用 Structure 之后,您可能必须对其进行一些其他代码操作,以确保 Java 保留对其(及其底层本机内存)的引用。

暂无
暂无

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

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