由於文章 https://www.pdai.tech/md/java/JVM/java-JVM-x-overview.html 已經把 JVM 講得很是詳細透徹,這裏再也不重複造輪子,只是看完後的一些結論和問題(或許還沒答案)總結,歡迎各位大佬在評論區留言並提問,我會不按期在評論區找出優質問題並回答,或許會提上本文正文。html
注:不必定是面試題java
看完類字節碼詳解的問題:面試
問:一個類的對象到底有多少字節spring
答: https://blog.csdn.net/qlmmys/article/details/53213857 segmentfault
看完類加載機制的結論:tomcat
一個類須要通過加載,鏈接,初始化 才能被使用,最後卸載,鏈接階段又包含驗證,準備和解析,準備階段負責給 static 變量賦 0 值,解析階段負責將符號引用轉變爲直接引用,可能在解析時遇到一個類名沒有加載過,就又須要去加載那個類,加載完成後會在方法區保存類的二進制字節流,而後建立一個 class 對象保存在堆區。springboot
類的加載階段可使用不一樣的加載器實現不同的加載方式,通常是使用默認的雙親委派加載模式。jvm
看完類加載機制後的問題:jsp
問:類加載器是用來加載類的,那誰來加載類加載器呢ide
答:啓動類加載器加載來加載其它類加載器
類加載器並不須要等到某個類被「首次主動使用」時再加載它,JVM規範容許類加載器在預料某個類將要被使用時就預先加載它,若是在預先加載的過程當中遇到了.class文件缺失或存在錯誤,類加載器必須在程序首次主動使用該類時才報告錯誤(LinkageError錯誤)若是這個類一直沒有被程序主動使用,那麼類加載器就不會報告錯誤。
問:一個類什麼時候會被加載,系統中那麼多的類,不可能所有加載進來吧
一個類只有在用到的時候纔會被加載,何爲用到,即須要用到它的 Class 對象了的時候,例如 :實例化,使用靜態方法或靜態變量,反射,main 方法的類
問:靜態代碼塊在何時執行,與靜態變量的執行前後,final 變量在哪一個階段賦值
答:靜態變量在準備階段就能夠在 方法區 中分配內存,並設置初始值,這個初始值是數據類型默認的 0 值,在初始化階段再賦予顯示指定的值
靜態塊在初始階段執行,當靜態塊使用了靜態變量須要靜態變量先申明瞭再能使用,以下
static { System.out.println(a); } static int a = 1; // 這時候是報錯的,Illegal forward refrence a 變量還未正確初始化
靜態代碼塊與靜態代碼塊是書寫順序執行的,代碼塊與代碼塊也是按照書寫順序執行的,嘗試一下小例子
static { System.out.println("何時加載"); } static { c = 3; System.out.println(c); }
關於 final 的使用,先看下面三個例子,可能顛覆你的認知,下面三種寫法都是正確的
final int b ; { b = 2; } final int d; public TestLoad(){ d = 4; } static final int c; static { c = 3; System.out.println(c); }
關於第一種和第二種,都是初始化實例變量,那誰先誰後呢,答案是代碼塊會比構造先執行,因此代碼塊會優先賦值,若是構造函數再次賦值會編譯出錯。
實例 final 常量是指在對象實例化後不可修改,所以能夠在構造函數,代碼塊和申明時對其賦值
靜態 final 常量是指在類初始化後不可修改,所以能夠在靜態代碼塊,申明時對其賦值
代碼塊沒法對靜態 final 常量賦值,由於靜態 final 常量須要在類初始化的時候賦值,後面就不能夠改了
子問:即然靜態變量在準備階段就分配內存並賦 0 值,那標記爲 final 的變量如何在初始化階段修改其值呢
猜(不知道答案):若是是 final 不會爲其賦 0 值
問:main 方法如何執行的
答:首先 main 方法確定要處於某一個類中,須要加載這個類,在初始化階段會執行靜態代碼塊,而後不會建立實例,也不會執行這個類的代碼塊,至關於調靜態方法同樣調起這個 main 函數所在的類
問:加載機制對應的一道很是經典的面試題
B 類繼承自 A 類,同時有構造方法,代碼塊,靜態代碼塊執行順序是怎麼樣的
答:根據上面的結論,靜態代碼塊在初始階段執行,代碼塊優先於構造函數,在構造子類的時候須要先構造父類,因此執行順序爲 父類靜態塊,子類靜態塊,父類代碼塊,父類構造函數,子類代碼塊,子類構造函數
問:若是 springboot 項目中我有一個類和某一個 jar 包中的類同類名同包名,會加載哪一個類; 兩個 jar 包中有同包同類名的類,會加載哪一個類
答:當前 classes 下有一個類和 jar 包中某個類同包同類名,則會使用當前 classes 下的類,這也是常常拿來覆蓋 jar 包中的類的辦法,若是兩個 jar 包中有同包同類名的類,會優先加載 -classpath
選項中寫在前面 jar 包中的類,這裏會這樣的緣由是由於工做目錄老是在 -classpath
中寫前 jar 包的前面的,若是啓動腳本不是寫在前面那就不能這麼幹了。
問:tomcat 的類加載機制
答: https://www.jianshu.com/p/51b2c50c58eb
看完 JVM 內存結構時的結論:
內存結構分爲:棧(Java 虛擬機棧,本地方法棧),堆(新生代 {伊甸園,倖存區from to },老年代),方法區,直接內存,程序計數器
看完 JVM 內存結構後的問題:
問:String str2 = new String("abc");
建立了幾個對象
答:初級必問答,網上有各類五花八門的答案 ,我這裏挑一個我認爲正確的,不服歡迎來辯 https://www.cnblogs.com/zhaideyou/p/5875175.html
問:方法區,永久代,元數據區怎麼理解
答:方法區是 JVM 規範,永久代和元數據區是其實現,邏輯上屬於堆的一部分,但爲了和堆進行區分,一般又叫非堆
由於愈來愈多的動態類生成,jsp 時代會有大量的 jsp 動態類,spring 的動態代理也會生成大量動態類,常常致使永久代內存溢出,因此在 1.7 開始,就開始把永久代的內存搬到其它地方,好比 1.7 版本 Jdk 就搬了 字符串常量池,這個不是空說的,有人作過驗證https://blog.csdn.net/kdy527/article/details/86511693
移動的內容包含
參考文章: https://blog.csdn.net/wuhenzhangxing/article/details/78224905
問:元數據區中存儲了些什麼信息,這個元空間是存儲在哪裏
答:jdk1.8 Metaspace 存儲在 native memory ,不會受 jvm 堆大小的約束,之前永久代也不會,只受限制於系統的內存和系統位數(32 位最大 4G )
元數據區主要存儲類的元數據信息了和類加載器信息
navtive memory 就是供 jvm 自身進程使用,主要保存這些信息
參考文章 : http://www.javashuo.com/article/p-xreiwkwk-bz.html
畫了一張圖,歡迎大神指正:
線程棧引用堆上的對象
參考資料彙總:
https://blog.csdn.net/kdy527/...https://blog.csdn.net/wuhenzh...
https://blog.csdn.net/u013721...
接下來的 Java 內存模型,垃圾回收及收集器參數調優,均可以直接看原文,暫時沒有什麼好的問題提出
個人博文大綱:https://blog.csdn.net/sanri1993/article/details/52201255