Jvm 相關文章讀後感包含一些個人面試經驗

由於文章 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

移動的內容包含

  • 符號引用被移到了native堆
  • 池化string對象被移到了java堆
  • Class對象、靜態變量被移到了java堆

參考文章: https://blog.csdn.net/wuhenzhangxing/article/details/78224905

問:元數據區中存儲了些什麼信息,這個元空間是存儲在哪裏

答:jdk1.8 Metaspace 存儲在 native memory ,不會受 jvm 堆大小的約束,之前永久代也不會,只受限制於系統的內存和系統位數(32 位最大 4G )

元數據區主要存儲類的元數據信息了和類加載器信息

navtive memory 就是供 jvm 自身進程使用,主要保存這些信息

  1. 管理java heap的狀態數據(用於GC);
  2. JNI調用,也就是Native Stack;
  3. JIT(即便編譯器)編譯時使用Native Memory,而且JIT的輸入(Java字節碼)和輸出(可執行代碼)也都是保存在Native Memory;
  4. NIO direct buffer。對於IBM JVM和Hotspot,均可以經過-XX:MaxDirectMemorySize來設置nio直接緩衝區的最大值。默認是64M。超過這個時,會按照32M自動增大。
  5. 對於IBM的JVM某些版本實現,類加載器和類信息都是保存在Native Memory中的。

參考文章 : http://www.javashuo.com/article/p-xreiwkwk-bz.html

畫了一張圖,歡迎大神指正:

線程棧引用堆上的對象

img

參考資料彙總:

https://blog.csdn.net/kdy527/...

https://blog.csdn.net/wuhenzh...

https://blog.csdn.net/u013721...

https://www.iteye.com/blog/ao...

https://www.pdai.tech/md/java...

接下來的 Java 內存模型,垃圾回收及收集器參數調優,均可以直接看原文,暫時沒有什麼好的問題提出
個人博文大綱:https://blog.csdn.net/sanri1993/article/details/52201255

相關文章
相關標籤/搜索