考慮下面的代碼示例:JMM保證調用
try (AutoClosable closable = new XXX()) {
o.method1(closable);
o.method2();
}
難道Java內存模型允許熱點重新排序closable.close()
o.method2()
過嗎?
我故意忽略像這樣的執行細節嗎?方法1捕獲可關閉嗎?在這個問題的第一部分。
我spefic的使用情況是這樣的:
我有一個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
不再是強可一旦當GC踢(JNA依靠finalize
釋放本機內存)
爲了防止這一點,我提出要繼承JNA的Memory
引入一個AutoClosableMemory
capture(m)
和內存將被釋放。這個想法是,使用try-with-resource構造會清楚地表明資源在這個範圍內是強烈可達的。我們可以釋放原生記憶的好處就是我們不再需要它,而不必等待GC(嘿,那是RAII!)。
try (AutoClosableMemory m = [...]) {
cApi.capture(m);
cApi.test();
}
我保證這m.close()
永遠cApi.test()
之前和m
是強可調用?在這種情況下,底層C API捕獲了m
,但是java編譯器無法知道它。
我一直在尋找類似於'它從不重新排列代碼圍繞本地指令'的東西,你有鏈接嗎? – Oleg
原生代碼塊在JLS中被形式化爲外部操作。它們意味着在與之前和之後的代碼關係之前發生。我曾經給過這個介紹,你可能會發現有幫助:https://youtu.be/XgiXKPEILoc我在第40分鐘談到外部行爲。 –
謝謝,優秀的談話。我想你應該把它添加到你的答案。你在[這裏](https://youtu.be/XgiXKPEILoc?t=40m37s)中談論的內容恰恰解決了OP的問題。 – Oleg