JMM保证在try-with-resource&中进行重新排序。 JNI打来电话

时间:2017-10-13 17:37:45

标签: java memory jna java-memory-model

给出以下代码示例:

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

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

我故意在这个问题的第一部分中省略了方法1捕获可关闭的实现细节吗?

我的特定用例是:

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

static char* value;

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

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

使用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());

第一个版本的问题是已经从Java分配m,并且此内存的生命周期与m强烈可达。一旦mcapture(m)不再强烈可达,当GC启动时,内存将被释放(JNA依赖finalize释放本机内存)

为了防止这种情况,我建议将JNA' Memory子类化为AutoClosableMemory。我们的想法是,使用try-with-resource构造可以清楚地说明资源在此范围内是可以很容易地访问的。奖励是我们可以释放本机内存,因为我们不再需要它而不必等待GC(嘿,那就是RAII!)。

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

我保证在m.close()之前永远不会调用cApi.test()并且m可以很容易地访问吗?在这种情况下,m由底层C API捕获,但java编译器无法知道它。

2 个答案:

答案 0 :(得分:4)

理论上,JVM可以重新排序指令,但方法的结果必须保持正确。 HotSpot不理解本机代码,为了保证正确性,它永远不会根据本机指令重新排序代码。

答案 1 :(得分:1)

对于一个线程,保证所有内容都以与代码中相同的顺序运行(任何发生的重新排序都不会影响您的程序)。重新排序只会影响其他线程如何看待发生的情况。在您的问题中,只有一个线程,因此您的程序可以保证在cApi.test()之前调用m.close()