给出以下代码示例:
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
强烈可达。一旦m
,capture(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编译器无法知道它。
答案 0 :(得分:4)
理论上,JVM可以重新排序指令,但方法的结果必须保持正确。 HotSpot不理解本机代码,为了保证正确性,它永远不会根据本机指令重新排序代码。
答案 1 :(得分:1)
对于一个线程,保证所有内容都以与代码中相同的顺序运行(任何发生的重新排序都不会影响您的程序)。重新排序只会影响其他线程如何看待发生的情况。在您的问题中,只有一个线程,因此您的程序可以保证在cApi.test()
之前调用m.close()
。