java - JMM 保证 try-with-resource 和 JNI 调用中的重新排序

标签 java memory jna java-memory-model

给出以下代码示例:

 try (AutoClosable closable = new XXX()) {
      o.method1(closable);  
      o.method2();
 }

Java 内存模型是否允许 HotSpot 在 o.method2() 之前重新排序 closable.close()

我在这个问题的第一部分故意省略了诸如does method1 captures closable?之类的实现细节。


我的具体用例是这样的:

我有一个 C 库,可以概括为:

static char* value;

void capture(char* ptr){
        value = ptr;
}

int len(void) {
    return strlen(value);
}

这个 native 库是使用 JNA 包装的

interface CApi extends Library {

 static {
   Native.register("test.so", CApi.class)
 }

  void capture(Pointer s);
  int test();
}

我原来的客户端代码看起来像这样:

cApi = Native.loadLibrary("test.so", CApi.class);


byte[] data = Native.toByteArray("foo");
Memory m = new Memory(data.length + 1);
m.write(0, data, 0, data.length);
m.setByte(data.length, (byte)0);

cApi.capture(m);
System.out.print(cApi.len());

第一个版本的问题是 m 是从 Java 分配的,并且该内存的生命周期与 m 的强可达性相关。一旦 capture(m) 就不再能够强烈访问 m,并且当 GC 启动时,内存将被释放(JNA 依赖 finalize 来释放 native 内存)

为了防止这种情况,我建议对 JNA 的 Memory 进行子类化,以引入 AutoClosableMemory。这个想法是,使用 try-with-resource 构造将清楚地表明该资源在此范围内是可以访问的。好处是我们可以在不再需要 native 内存时立即释放它,而不必等待 GC(嘿,这就是 RAII!)。

try (AutoClosableMemory m = [...]) {
  cApi.capture(m);
  cApi.test();
}

我能否保证 m.close()cApi.test() 之前永远不会被调用,并且 m 是强可达的?在这种情况下,m 被底层 C API 捕获,但 java 编译器无法知道它。

最佳答案

理论上,JVM 可以对指令重新排序,但方法的结果必须保持正确。 HotSpot 不理解 native 代码,为了保证正确性,它从不围绕 native 指令重新排序代码。

关于java - JMM 保证 try-with-resource 和 JNI 调用中的重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46735264/

相关文章:

c - 这段代码有什么作用?内存分配

c++ - 指针的内存使用情况

Java JNA编写win32 API的自定义COM接口(interface)

java - 如何将 "manual animation"设计成没有代码延迟的 Android 游戏

java - 可以通过合并对可变对象的引用来公开内部表示

java - 当设备与地面不平时查找方位角值 - Android?

java - 有没有有效的方法使用 JNA 读取动态大小共享内存段?

java - 如何在Eclipse中安装Web动态模块?

c++ - C++/ActiveX用malloc,memcpy,free替换了realloc。功能和性能测试

java - 线程 "main"java.lang.Error : Invalid memory access(Unknown Source) 中的 JNA 异常