jvm java 看似一種語言,實則一個巨大的體系的王國,開發這么多年了,還是沒有搞懂,我以為我懂了,可是過了一段時間又忘了,所以說還是沒懂
1、main方法說起
編譯完我們的java文件后,需要有個一含有main方法的類,java 命令將指示操作系統啟動一個jvm進程
這個jvm進程啟動后,尋找那個main地方開始執行程序
java [JVM_Options] ClassName_with_main [args_separate_space]
main方法的簽名必須是 pubic static void main(String[] args) why?
簡單點:
首先,main方法是JVM(java虛擬機)自動調用
JVM調用main方法的位置自然不會在某個類中、或某個包中,因此只有當main方法在公有級別上時,才對JVM可見,所以mian方法需要public修飾,
main方法所在的類也需要public修飾符。
由於main方法是所有程序的入口,也就是main被調用時沒有任何對象創建,不通過對象調用某一方法,只有將該方法定義為靜態方法,所以main方法是一個靜態方法,既需要static修飾。
JVM對於java程序已經是最底層,由它調用的方法的返回值已經沒有任何地方可去,因此,main方法返回值為空,既需用void修飾。
至於main方法的參數String[ ] arg我們現在已經很少有機會去用它了,它用於在接受命令行傳入的參數
2、執行main方法之前發生了神馬
可以參看 jvm源碼分析
首先要明確 jvm進程 是操作系統的進程,該進程是多線程機制的
我們明確兩種線程:
jvm線程:指jvm自行管理的線程,我們在程序中無法操控,多是守護類型的
java線程:指從java技術角度看 jvm、我們在程序中用Thread類或Runnable接口編寫產生的線程,可操控的線程
至於 java線程 在 jvm里面是怎么實現的,怎么對應到os級別的線程的,請看 http://my.oschina.net/jingxing05/blog/275334
明確兩類不同的線程之后,執行main方法之前: LoadJavaVM
jvm進程啟動了多個jvm線程(很可能是錯的,如有,請賜教):
jvm線程:
-
啟動 VM Thread, 單例的,所有線程之始祖!這個線程自輪詢loop從對一個隊列中取操作任務,來產生其他線程
-
根據jvm抽象規范,可能有執行引擎線程,GC線程,classloader線程
在jvm自身啟動和初始化之后,會
ContinueInNewThread(JavaMain, threadStackSize, (void*)&args);
即啟動一個叫main的線程來執行 入口的main方法,main線程雖然不是我們手動生出的線程,但ta還是一個非守護線程
3、main執行過程
-
加載類
執行main方法時,jvm進程發現main所在類沒有在方法區,於是開始進行classload
類加載完的最后一步是 根據情況決定 是不是要進行類的初始化
在main執行之前,必須先對類進行初始化。初始化類的變量,還有靜態代碼塊。初始化的時候還要先初始化它的父類。每個類都有一個隱含的父類Object。
初始化的順序:類變量和靜態塊按序,先父后子
類的初始化過程發生時刻:
1. T是一個類,當T的一個實例創建的時候,也就是T t = new T();
2. T的一個靜態方法被調用的時候,也就是 T.staticField();
3. T的靜態屬性被賦值的時候,T.staticField = o;
4. T的一個靜態屬性被使用的時候,也就是 Object o = T.staticField; 但是它不是常量。
5. T is a top level class , and an assert statement lexically nested
within T is executed. (不懂,求解)
-
執行main方法
將方法需要的參數,局部變量,本地方法,操作數等以 棧幀的結構 push到 main線程的堆棧區,然后執行引擎線程開始執行,執行完畢,將該棧幀 pop掉。main線程的堆棧區沒有棧幀時,main線程消退。
-
卸載類對象
這一步是個優化的步驟,釋放一些方法區的內存,jvm自己決定要不要這一步,一般不會去卸載方法區的
-
程序退出
1. 所有的非daemon線程都終止了
2. 某個線程調用了類Runtime或者System的exit方法
main程序執行圖
類加載詳細過程
jvm中的一些線程可參看 http://ifeve.com/jvm-thread/
http://my.oschina.net/jingxing05/blog/282867?p={{currentPage+1}}