Java實習生每日10道面試題打卡——JVM篇

      網友投稿 633 2022-05-30

      臨近秋招,備戰暑期實習,祝大家每天進步億點點!==打卡 Day06==!

      有粉絲大佬要求更新有難度的,所以本篇總結的是 JVM 相關的面試題,后續會每日更新~

      注:JVM 比較枯燥,直接刷題前,最好先去串一遍 JVM 課程,這里推薦傳智播客的 JVM 教程:黑馬程序員JVM教程筆記完整目錄

      ![在這里插入圖片描述](https://img-blog.csdnimg.cn/20210522175819650.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU5MTk4MA==,size_16,color_FFFFFF,t_70#pic_center =400x400)

      1、請你簡述一下 Java 內存結構(運行時數據區)

      如圖所示:

      ① 程序計數器

      程序計數器:==線程私有==。一塊較小的內存空間,程序計數器用于保存 JVM 中下一條所要執行的字節碼指令的地址!如果正在執行的是 Native 方法,則這個計數器值則為空。程序計數器在硬件層面是通過 寄存器 實現的!

      Java指令執行流程:

      .java代碼源文件經過編譯為.class 二進制字節碼文件。

      .class 文件中的每一條二進制字節碼指令(JVM指令) 通過 解釋器 轉換成 機器碼 然后就可以被 CPU 執行了!

      當 解釋器 將一條 jvm 指令轉換成 機器碼 后,同時會向程序計數器 遞交下一條 jvm 指令的執行地址!

      如圖所示:

      ② 虛擬機棧

      虛擬機棧:==線程私有==,它的生命周期與線程相同。虛擬機棧是Java方法執行的內存模型,每個方法在執行的同時都會創建一個棧幀用于存儲局部變量表、操作數棧、動態鏈接、方法出口等信息。每一個方法從被調用直至執行完成的過程,就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。

      每個棧由多個棧幀(Frame) 組成,對應著每個方法運行時所占用的內存。

      每個線程只能有一個活動棧幀,對應著當前正在執行的方法,當方法執行時壓入棧,方法執行完畢后彈出棧。

      方法體中的引用變量和基本類型的變量都在棧上,其他都在堆上。

      實例代碼:

      /** * @Auther: csp1999 * @Date: 2020/11/10/11:36 * @Description: 演示棧幀 */ public class Demo01 { public static void main(String[] args) { methodA(); } private static void methodA() { methodB(1, 2); } private static int methodB(int a, int b) { int c = a + b; return c; } }

      流程分析:

      我們打斷點來Debug 一下看一下方法執行的流程:

      接這往下走,使方法B執行完畢:

      然后方法A 執行完畢,其對應的棧幀出棧,main 方法對應的棧幀為活動棧幀;最后main執行完畢,棧幀出棧,虛擬機棧為空,代碼運行結束!

      ③ 本地方法棧

      本地方法棧:==線程私有==。本地方法棧與虛擬機棧所發揮的作用是非常相似的,它們之間的區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則為虛擬機使用到的 Native 方法服務。

      一些帶有native 關鍵字修飾的方法就是需要JAVA去調用本地的C或者C++方法,因為JAVA有時候沒法直接和操作系統底層交互,所以需要用到本地方法!

      ④ 堆

      堆:==線程共享==。Java堆是Java虛擬機所管理的內存中最大的一塊,是被所有線程共享的一塊內存區域,在虛擬機啟動時創建。Java堆的唯一目的就是存放對象實例,幾乎所有的對象實例都在這里分配內存。

      通過new關鍵字創建的對象都會被放在堆內存。

      方法體中的引用變量和基本類型的變量都在棧上,其他都在堆上。

      Java 堆是垃圾收集器管理的主要區域,因此很多時候也被稱做“GC 堆”(Garbage)。

      -Xmx -Xms:JVM初始分配的堆內存由-Xms指定,默認是物理內存的1/64。

      ⑤ 方法區

      方法區:==線程共享==。方法區用于存儲已被虛擬機加載的 *類信息(構造方法、接口定義)、常量、靜態變量、即時編譯器編譯后的代碼(字節碼)*等數據。

      (Java實習生)每日10道面試題打卡——JVM篇

      方法區在 JVM 啟動的時候被創建,并且它的實際的物理內存空間和 Java堆一樣都可以是不連續的, 關閉 Jvm 就會釋放這個區域的內存。

      方法區的大小決定了系統可以保存多少個類,如果系統定義了太多的類,導致方法區溢出,虛擬機同樣會拋出內存溢出錯誤:(java.lang.OutOfMemoryError:PermGen space、java.lang.OutOfMemoryError:Metaspace)。

      注意:方法區時一種規范,而==永久代和元空間==是它的2種實現方式。

      方法區的演進:

      1.6 版本方法區是由 永久代 實現(使用堆內存的一部分作為方法區),且由JVM 管理。由Class、ClassLoader、常量池(包括StringTable) 組成。

      Jdk 1.7 版本仍有永久代,但已經逐步 " 去永久代 ",StringTable、靜態變量從永久代移除,保存在堆中。

      1.8 版本后,方法區交給本地內存管理,而脫離了JVM,由元空間實現(元空間不再使用堆的內存,而是使用本地內存,即操作系統的內存),由Class、ClassLoader、常量池(StringTable 被移到了堆中管理) 組成。

      ⑥ 運行時常量池

      常量池:可以看做是一張表,虛擬機指令根據這張常量表找到要執行的 類名,方法名,參數類型、字面量 等信息。

      常量池是*.class文件中的,當該類被加載以后,它的常量池信息就會放入運行時常量池,并把里面的符號地址變為真實內存地址。

      運行時常量池:是方法區的一部分。

      String str = new String("hello");

      上面的語句中變量 str 放在棧上,用 new 創建出來的字符串對象放在堆上,而hello這個字面量是放在堆中。

      2、請問jvm垃圾回收是否涉及棧內存?

      不需要。因為虛擬機棧中是由一個個棧幀組成的,在方法執行完畢后,對應的棧幀就會被彈出棧。所以無需通過垃圾回收機制去回收內存。

      3、虛擬機棧內存的分配越大越好嗎?

      不是。因為物理內存是一定的,棧內存越大,可以支持更多的遞歸調用,但是可執行的線程數就會越少。

      我們來看一張圖:

      舉例:如果物理內存是500M(假設),如果一個線程所能分配的棧內存為2M的話,那么可以有250個線程。而如果一個線程分配棧內存占5M的話,那么最多只能有100 個線程同時執行!

      4、從JVM的角度分析,方法內的局部變量是否是線程安全的?

      我們通過兩張圖去分析一下:

      情況一:

      情況二:

      從圖中得出:局部變量如果是靜態的可以被多個線程共享,那么就存在線程安全問題。如果是非靜態的只存在于某個方法作用范圍內,被線程私有,那么就是線程安全的!

      再來看一個案例:

      /** * 局部變量的線程安全問題 */ public class Demo02 { public static void main(String[] args) {// main 函數主線程 StringBuilder sb = new StringBuilder(); sb.append(4); sb.append(5); sb.append(6); new Thread(() -> {// Thread新創建的線程 m2(sb); }).start(); } public static void m1() { // sb 作為方法m1()內部的局部變量,是線程私有的 ---> 線程安全 StringBuilder sb = new StringBuilder(); sb.append(1); sb.append(2); sb.append(3); System.out.println(sb.toString()); } public static void m2(StringBuilder sb) { // sb 作為方法m2()外部的傳遞來的參數,sb 不在方法m2()的作用范圍內 // 不是線程私有的 ---> 非線程安全 sb.append(1); sb.append(2); sb.append(3); System.out.println(sb.toString()); } public static StringBuilder m3() { // sb 作為方法m3()內部的局部變量,是線程私有的 StringBuilder sb = new StringBuilder();// sb 為引用類型的變量 sb.append(1); sb.append(2); sb.append(3); return sb;// 然而方法m3()將sb返回,sb逃離了方法m3()的作用范圍,且sb是引用類型的變量 // 其他線程也可以拿到該變量的 ---> 非線程安全 // 如果sb是非引用類型,即基本類型(int/char/float...)變量的話,逃離m3()作用范圍后,則不會存在線程安全 } }

      所以,該面試題答案是:

      如果方法內局部變量沒有逃離方法的作用范圍,則是線程安全的。

      如果局部變量引用了對象,并逃離了方法的作用范圍,則需要考慮線程安全問題。

      5、虛擬機棧內存溢出的情況有哪些?

      1.虛擬機棧中,棧幀過多(方法無限遞歸)導致棧內存溢出,這種情況比較常見!

      2.每個棧幀所占用內存過大(某個/某幾個棧幀內存直接超過虛擬機棧最大內存),這種情況比較少見!

      如圖所示,就是棧中棧幀過多的情況:

      6、請你說一下JVM運行時數據區方法區的演進?

      1.6 版本方法區是由永久代實現(使用堆內存的一部分作為方法區),且由JVM 管理。由Class、ClassLoader、常量池(包括StringTable) 組成。

      靜態變量就存放在永久代(方法區)上。

      Jdk 1.7 版本仍有永久代,但已經逐步 " 去永久代 ",StringTable、靜態變量從永久代移除,保存在堆中。

      1.8 版本后,方法區交給本地內存管理,而脫離了JVM,由元空間實現(元空間不再使用堆的內存,而是使用本地內存,即操作系統的內存),由Class、ClassLoader、常量池(StringTable 被移到了堆中管理) 組成。

      靜態變量、StringTable 存放在堆中!

      為什么要用元空間取代永久代?

      因為永久代有以下幾個弊端:

      ① 字符串常量池存在于永久代中,在大量使用字符串的情況下,非常容易出現OOM的異常。

      ② JVM加載的class的總數,方法的大小等都很難確定,因此對永久代大小的指定難以確定。太小的永久代容易導致永久代內存溢出,太大的永久代則容易導致虛擬機內存緊張,空間浪費。

      ③ 永久代進行調優很困難:方法區的垃圾收集主要回收兩部分,常量池中廢棄的常量和不再使用的類。而不再使用的類或類的加載器回收比較復雜,FULL GC 的時間長。

      7、請問Java虛擬機中有哪些類加載器?

      以 JDK 8 為例:

      類加載器的優先級(由高到低):啟動類加載器 -> 擴展類加載器 -> 應用程序類加載器 -> 自定義類加載器。

      **啟動類加載器(Bootstrap ClassLoader):**這個類加載器負責將存放在 JAVA_HOME/jre/lib 目錄中的,或者被-Xbootclasspath 參數所指定的路徑中的,并且是虛擬機識別的(僅按照文件名識別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會被加載)類庫加載到虛擬機內存中。

      **擴展類加載器(Extension ClassLoader):**這個加載器由 sun.misc.Launcher$ExtClassLoader 實現,它負責加載JAVA_HOME/jre/lib/ext目錄中的,或者被 java.ext.dirs 系統變量所指定的路徑中的所有類庫,開發者可以直接使用擴展類加載器。

      **應用程序類加載器(Application ClassLoader):**這個類加載器由 sun.misc.Launcher$AppClassLoader 實現。由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統類加載器。它負責加載用戶類路徑(ClassPath)上所指定的類庫,開發者可以直接使用這個類加載器,如果應用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認的類加載器。

      **自定義類加載器:**用戶自定義的類加載器。

      8、請你說一下類的加載的過程?

      類加載的過程包括:加載、驗證、準備、解析、初始化。其中驗證、準備、解析統稱為連接。

      加載:通過一個類的全限定名來獲取定義此類的二進制字節流,在內存中生成一個代表這個類的java.lang.Class對象。

      驗證:確保 Class 文件的字節流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全。

      準備:為靜態變量分配內存并設置靜態變量初始值,這里所說的初始值“通常情況”下是數據類型的零值。

      解析:將常量池內的符號引用替換為直接引用。

      初始化:到了初始化階段,才真正開始執行類中定義的 Java 初始化程序代碼。主要是靜態變量賦值動作和靜態語句塊(static{})中的語句。

      9、請你說一下什么是雙親委派模型?

      如圖所示:

      什么是雙親委派模型?

      如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去加載。

      為什么要使用雙親委派模型呢?(好處)

      避免重復加載 + 避免核心類篡改

      采用雙親委派模式的是好處是Java類隨著它的類加載器一起具備了一種帶有優先級的層次關系,通過這種層級關可以避免類的重復加載,當父加載器已經加載了該類時,就沒有必要子加載器再加載一次。

      其次是考慮到安全因素,java 核心 api 中定義類型不會被隨意替換,假設通過網絡傳遞一個名為 java.lang.Integer 的類,通過雙親委托模式傳遞到啟動類加載器,而啟動類加載器在核心Java API發現這個名字的類,發現該類已被加載,并不會重新加載網絡傳遞的過來的 java.lang.Integer,而直接返回已加載過的 Integer.class,這樣便可以防止核心API庫被隨意篡改。

      10、說一下虛擬機棧和堆的區別?

      ① 物理地址方面的區別:

      堆 的物理地址分配對對象是不連續的。因此性能慢些。

      虛擬機棧 使用的是數據結構中的棧,先進后出的原則,物理地址分配是連續的。所以性能快。

      ② 內存分配方面的區別:

      堆 因為是不連續的,所以分配的內存是在運行期確認的,因此大小不固定。一般堆大小遠遠大于虛擬機棧。

      虛擬機棧 是連續的,所以分配的內存大小要在編譯期就確認,大小是固定的。

      ③ 存放的內容方面的區別:

      堆 存放的是對象的實例和數組。因此該區更關注的是數據的存儲。

      虛擬機棧 存放的是局部變量,操作數棧,返回結果。該區更關注的是程序方法的執行。

      注:靜態變量放在方法區,而靜態的對象還是放在堆。

      ④ 線程共享方面的區別:

      堆 對于整個應用程序都是共享、可見的。

      虛擬機棧 只對于線程是可見的。所以也是線程私有。他的生命周期和線程相同。

      參考文章:

      JVM_01 內存結構(程序計數器、虛擬機棧、本地方法棧)

      JVM_02-03 內存結構(堆、方法區)

      JVM_11 類加載與字節碼技術 (類加載與類的加載器)

      總結的面試題也挺費時間的,文章會不定時更新,有時候一天多更新幾篇,如果幫助您復習鞏固了知識點,還請三連支持一下,后續會億點點的更新!

      Java JVM 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:大數據下單集群如何做到2萬+規模?
      下一篇:推薦系統的常用指標
      相關文章
      亚洲不卡1卡2卡三卡2021麻豆| 亚洲国产视频久久| 亚洲日本va午夜中文字幕一区| 免费在线观看亚洲| 亚洲成av人无码亚洲成av人| 亚洲日本久久久午夜精品 | 精品亚洲成a人片在线观看少妇| 国产成A人亚洲精V品无码| 久久青青草原亚洲av无码| 国产亚洲精彩视频| 亚洲第一区精品日韩在线播放| 一本色道久久88亚洲综合 | 中文字幕亚洲色图| 99久久精品国产亚洲| 亚洲国产精品久久久久婷婷软件 | 亚洲爆乳无码专区www| 亚洲日韩精品无码专区加勒比☆| 国产亚洲精品VA片在线播放| 亚洲中文字幕乱码AV波多JI| 亚洲乱妇熟女爽到高潮的片| 国产AV无码专区亚洲AV麻豆丫| 18禁亚洲深夜福利人口| 国产亚洲视频在线| 亚洲国产香蕉人人爽成AV片久久 | 国产亚洲情侣一区二区无码AV| 不卡精品国产_亚洲人成在线| 中文字幕精品亚洲无线码一区| 亚洲日产无码中文字幕| 久久精品国产亚洲麻豆| 西西人体44rt高清亚洲| 亚洲精品国产福利片| 激情内射亚洲一区二区三区爱妻| 亚洲性色精品一区二区在线| 亚洲国产一区二区三区在线观看| 偷自拍亚洲视频在线观看| 中文字幕亚洲无线码a| 久久亚洲伊人中字综合精品| 亚洲精品视频久久| 亚洲中文无码卡通动漫野外| 18禁亚洲深夜福利人口| 在线A亚洲老鸭窝天堂|