发生第二次回调调用时 Jvm 崩溃



我使用 JNA 调用本机库

我的回调接口

public interface PPAEvent extends Callback{
void callback(int eventCode, int opCode, String Data);
}

我有一个回调实现

public class PPAEventImpl implements PPAEvent{
public void callback(int eventCode, int opCode, String Data) {
System.out.println("eventCode : "+eventCode);
System.out.println("opCode : "+opCode);
System.out.println("Data : "+Data);
}
}

和库类,如

public interface PAapiMapping extends Library{
int PAHandShake( int lOperationCode, String sServerAddress, Callback pEventFunc);
int PAControl(String sData);
int PARequest(int lOperationCode, String sInputData);
}

我正在调用上述库方法。类似的东西

PAapiMapping PAapi = (PAapiMapping) Native.load("PAapi", PAapiMapping.class);
PPAEventImpl pPAEvent = new PPAEventImpl();
int result1 = PAapi.PAHandShake(1, "ip", paEventstatic);
System.out.println("result1 : " + result1);
int result2 = PAapi.PAControl(getXML());
System.out.println("result2 : " + result2);
int result3 = PAapi.PARequest(19, "");
System.out.println("result3 : " + result3);
TimeUnit.SECONDS.sleep(20);
System.out.println("Execution over");

我从第三方库文档中了解到的是,我调用的方法(如 PARequest(将对回调方法进行多次调用 回调方法执行一次,然后 JVM 崩溃。我是JNA的新手,不知道我做错了什么。基本上我想要的是相同的回调来处理所有事件。

所呈现代码的问题在于,回调不是由硬引用保存的:

PAapiMapping PAapi = (PAapiMapping) Native.load("PAapi", PAapiMapping.class);
PPAEventImpl pPAEvent = new PPAEventImpl();
int result1 = PAapi.PAHandShake(1, "ip", paEventstatic);
// (1)
System.out.println("result1 : " + result1);
// (2)
int result2 = PAapi.PAControl(getXML());
System.out.println("result2 : " + result2);
int result3 = PAapi.PARequest(19, "");
System.out.println("result3 : " + result3);
TimeUnit.SECONDS.sleep(20);
System.out.println("Execution over");
// (3)
// Reference.reachabilityFence(pPAEvent);

在第(1(点,pPAEvent引用的对象符合 GC 的条件 - 回调在传递给本机时被保存,因为 VM 无法通过 JNI barier 查看,但在调用返回PAHandShake后,可以收集对象。

当到达(2(并且发生下一个本机调用时,回调可能仍在原位(没有发生 GC(。在这种情况下,调用成功或 GC 已发生,并且回调已被删除。在这种情况下,将发生未定义的行为(在大多数情况下会发生崩溃(。

您需要确保回调保持硬引用。有多种选项 - 上面位置(3(中显示的选项适用于 Java 9+。它将确保硬引用一直保留到最后。另一种选择是使用静态字段来保存引用 - 这些通常仅在卸载类时收集。

最新更新