jit動態編譯的時候,有可能會造成乙個非常經典的指令重排
public class myobject
public void execute()
}// 執行緒1:
myobject myobj = new myobject(); => 這個是我們自己寫的一行**
// 執行緒2:
myobj.execute();
// 步驟1:以myobject類作為原型,
// 給他的物件例項分配一塊記憶體空間,
//objref就是指向了分配好的記憶體空間的位址的引用,指標
objref = allocate(myobject.class);
// 步驟2:就是針對分配好記憶體空間的乙個物件例項,執行他的建構函式,對這個物件例項進行初始化的操作,執行我們自己寫的建構函式裡的一些**,對各個例項變數賦值,初始化的邏輯
invokeconstructor(objref);
// 步驟3:上兩個步驟搞定之後,乙個物件例項就搞定了,此時就是把objref指標指向的記憶體位址,賦值給我們自己的引用型別的變數,myobj就可以作為乙個類似指標的概念指向了myobject物件例項的記憶體位址
myobj = objref;
有可能jit動態編譯為了加速程式的執行速度,因為步驟2是在初始化乙個物件例項,這個步驟是有可能很耗時的,比如說你可能會在裡面執行一些網路的通訊,磁碟檔案的讀寫,都有可能。
jit動態編譯,指令重排,為了加速程式的執行效能和效率,可能會重排為,步驟1 -> 步驟3 -> 步驟2。
執行緒1,剛剛執行完了步驟1和步驟3,步驟2還沒執行,此時myobj已經不是null了,但是myobject物件例項內部的resource是null。
執行緒2,直接呼叫myobj.execute()方法, 此時內部會呼叫resource.execute()方法,但是此時resource是null,直接導致空指標。
double check單例模式裡面,就是可能會出現這樣的jit指令重排,如果你不加volatile關鍵字,會導致一些問題的發生,volatile是避免說步驟1、步驟3、步驟2,必須全部執行完畢了,此時才能試用myobj物件例項。
編譯器對操作的重新排序
include include volatile int start 4 volatile int done 4 void work void param printf thread i started n id double total 0 for int i 0 i 100000000 i pr...
D語言中的編譯器指令(Pragma)
pragma pragma 標誌符 pragma 標誌符,表示式列表 pragma pragma identifier pragma identifier,expressionlist 編譯器指令用來給編譯器傳遞如何使用產品提供商對d的特殊擴充套件的資訊。指令以 結尾,它們可以影響一條語句 一塊語句...
C C 編譯器對struct大小的處理
一 什麼是對齊,以及為什麼要對齊 1.現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何位址開始,但實際情況是在訪問特定變數的時候經常在特定的記憶體位址訪問,這就需要各型別資料按照一定的規則在空間上排列,而不是順序的乙個接乙個的排放,這就是對齊。2.對齊的作...