亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

打卡每日10道面試題——JVM篇

 更新時間:2021年06月15日 17:02:46   作者:興趣使然的草帽路飛興趣使然的草帽路飛  
總結(jié)了JVM一些經(jīng)典面試題,分享出我自己的解題思路,希望對大家有幫助,有哪里你覺得不正確的話,歡迎指出,后續(xù)有空會更新,希望大家能夠喜歡

1、請你簡述一下 Java 內(nèi)存結(jié)構(gòu)(運(yùn)行時數(shù)據(jù)區(qū))

如圖所示:

在這里插入圖片描述

① 程序計(jì)數(shù)器

  • 程序計(jì)數(shù)器:線程私有。一塊較小的內(nèi)存空間,程序計(jì)數(shù)器用于保存 JVM 中下一條所要執(zhí)行的字節(jié)碼指令的地址!如果正在執(zhí)行的是 Native 方法,則這個計(jì)數(shù)器值則為空。程序計(jì)數(shù)器在硬件層面是通過 寄存器 實(shí)現(xiàn)的!

Java指令執(zhí)行流程

  • java代碼源文件經(jīng)過編譯為.class 二進(jìn)制字節(jié)碼文件。
  • class 文件中的每一條二進(jìn)制字節(jié)碼指令(JVM指令) 通過 解釋器 轉(zhuǎn)換成 機(jī)器碼 然后就可以被 CPU 執(zhí)行了!
  • 當(dāng) 解釋器 將一條 jvm 指令轉(zhuǎn)換成 機(jī)器碼 后,同時會向程序計(jì)數(shù)器 遞交下一條 jvm 指令的執(zhí)行地址!

如圖所示:

在這里插入圖片描述

② 虛擬機(jī)棧

  • 虛擬機(jī)棧:線程私有,它的生命周期與線程相同。虛擬機(jī)棧是Java方法執(zhí)行的內(nèi)存模型,每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每一個方法從被調(diào)用直至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機(jī)棧中入棧到出棧的過程。
    • 每個棧由多個棧幀(Frame) 組成,對應(yīng)著每個方法運(yùn)行時所占用的內(nèi)存。
    • 個線程只能有一個活動棧幀,對應(yīng)著當(dāng)前正在執(zhí)行的方法,當(dāng)方法執(zhí)行時壓入棧,方法執(zhí)行完畢后彈出棧。
    • 方法體中的引用變量和基本類型的變量都在棧上,其他都在堆上。

實(shí)例代碼:

/**
 * @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;
    }
}

流程分析:

在這里插入圖片描述

我們打斷點(diǎn)來Debug 一下看一下方法執(zhí)行的流程:

在這里插入圖片描述

接這往下走,使方法B執(zhí)行完畢:

在這里插入圖片描述

然后方法A 執(zhí)行完畢,其對應(yīng)的棧幀出棧,main 方法對應(yīng)的棧幀為活動棧幀;最后main執(zhí)行完畢,棧幀出棧,虛擬機(jī)棧為空,代碼運(yùn)行結(jié)束!

③ 本地方法棧

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

一些帶有native 關(guān)鍵字修飾的方法就是需要JAVA去調(diào)用本地的C或者C++方法,因?yàn)镴AVA有時候沒法直接和操作系統(tǒng)底層交互,所以需要用到本地方法!

④ 堆

堆:線程共享。Java堆是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,是被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動時創(chuàng)建。Java堆的唯一目的就是存放對象實(shí)例,幾乎所有的對象實(shí)例都在這里分配內(nèi)存。 通過new關(guān)鍵字創(chuàng)建的對象都會被放在堆內(nèi)存。方法體中的引用變量和基本類型的變量都在棧上,其他都在堆上。Java 堆是垃圾收集器管理的主要區(qū)域,因此很多時候也被稱做“GC 堆”(Garbage)。-Xmx -Xms:JVM初始分配的堆內(nèi)存由-Xms指定,默認(rèn)是物理內(nèi)存的1/64。

⑤ 方法區(qū)

方法區(qū):線程共享。方法區(qū)用于存儲已被虛擬機(jī)加載的 *類信息(構(gòu)造方法、接口定義)、常量、靜態(tài)變量、即時編譯器編譯后的代碼(字節(jié)碼)*等數(shù)據(jù)。 方法區(qū)在 JVM 啟動的時候被創(chuàng)建,并且它的實(shí)際的物理內(nèi)存空間和 Java堆一樣都可以是不連續(xù)的, 關(guān)閉 Jvm 就會釋放這個區(qū)域的內(nèi)存。方法區(qū)的大小決定了系統(tǒng)可以保存多少個類,如果系統(tǒng)定義了太多的類,導(dǎo)致方法區(qū)溢出,虛擬機(jī)同樣會拋出內(nèi)存溢出錯誤:(java.lang.OutOfMemoryError:PermGen space、java.lang.OutOfMemoryError:Metaspace)。 注意:方法區(qū)時一種規(guī)范,而永久代和元空間是它的2種實(shí)現(xiàn)方式。

方法區(qū)的演進(jìn):

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

在這里插入圖片描述

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

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

⑥ 運(yùn)行時常量池

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

常量池是*.class文件中的,當(dāng)該類被加載以后,它的常量池信息就會放入運(yùn)行時常量池,并把里面的符號地址變?yōu)檎鎸?shí)內(nèi)存地址。

運(yùn)行時常量池:是方法區(qū)的一部分。

String str = new String("hello");

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

2、請問jvm垃圾回收是否涉及棧內(nèi)存?

不需要。因?yàn)樘摂M機(jī)棧中是由一個個棧幀組成的,在方法執(zhí)行完畢后,對應(yīng)的棧幀就會被彈出棧。所以無需通過垃圾回收機(jī)制去回收內(nèi)存。

3、虛擬機(jī)棧內(nèi)存的分配越大越好嗎?

  • 不是。因?yàn)槲锢韮?nèi)存是一定的,棧內(nèi)存越大,可以支持更多的遞歸調(diào)用,但是可執(zhí)行的線程數(shù)就會越少。

我們來看一張圖:

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

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

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

情況一:

情況二:

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

再來看一個案例

/**
 * 局部變量的線程安全問題
 */
public class Demo02 {
    public static void main(String[] args) {// main 函數(shù)主線程
        StringBuilder sb = new StringBuilder();
        sb.append(4);
        sb.append(5);
        sb.append(6);
        new Thread(() -> {// Thread新創(chuàng)建的線程
            m2(sb);
        }).start();
    }
    public static void m1() {
        // sb 作為方法m1()內(nèi)部的局部變量,是線程私有的 ---> 線程安全
        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()外部的傳遞來的參數(shù),sb 不在方法m2()的作用范圍內(nèi)
        // 不是線程私有的 ---> 非線程安全
        sb.append(1);
        sb.append(2);
        sb.append(3);
        System.out.println(sb.toString());
    }
    public static StringBuilder m3() {
        // sb 作為方法m3()內(nèi)部的局部變量,是線程私有的
        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()作用范圍后,則不會存在線程安全
    }
}

所以,該面試題答案是:

如果方法內(nèi)局部變量沒有逃離方法的作用范圍,則是線程安全的。如果局部變量引用了對象,并逃離了方法的作用范圍,則需要考慮線程安全問題。

5、虛擬機(jī)棧內(nèi)存溢出的情況有哪些?

  • 1.虛擬機(jī)棧中,棧幀過多(方法無限遞歸)導(dǎo)致棧內(nèi)存溢出,這種情況比較常見!
  • 2.每個棧幀所占用內(nèi)存過大(某個/某幾個棧幀內(nèi)存直接超過虛擬機(jī)棧最大內(nèi)存),這種情況比較少見!

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

在這里插入圖片描述

6、請你說一下JVM運(yùn)行時數(shù)據(jù)區(qū)方法區(qū)的演進(jìn)?

  • 1.6 版本方法區(qū)是由永久代實(shí)現(xiàn)(使用堆內(nèi)存的一部分作為方法區(qū)),且由JVM 管理。由Class、ClassLoader、常量池(包括StringTable) 組成。
  • 靜態(tài)變量就存放在永久代(方法區(qū))上。

在這里插入圖片描述

  • Jdk 1.7 版本仍有永久代,但已經(jīng)逐步 " 去永久代 ",StringTable、靜態(tài)變量從永久代移除,保存在堆中。
  • 1.8 版本后,方法區(qū)交給本地內(nèi)存管理,而脫離了JVM,由元空間實(shí)現(xiàn)(元空間不再使用堆的內(nèi)存,而是使用本地內(nèi)存,即操作系統(tǒng)的內(nèi)存),由Class、ClassLoader、常量池(StringTable 被移到了堆中管理) 組成。
  • 靜態(tài)變量、StringTable 存放在堆中!

在這里插入圖片描述

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

因?yàn)橛谰么幸韵聨讉€弊端:

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

JVM加載的class的總數(shù),方法的大小等都很難確定,因此對永久代大小的指定難以確定。太小的永久代容易導(dǎo)致永久代內(nèi)存溢出,太大的永久代則容易導(dǎo)致虛擬機(jī)內(nèi)存緊張,空間浪費(fèi)。

③ 永久代進(jìn)行調(diào)優(yōu)很困難:方法區(qū)的垃圾收集主要回收兩部分,常量池中廢棄的常量和不再使用的類。而不再使用的類或類的加載器回收比較復(fù)雜,F(xiàn)ULL GC 的時間長。

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

以 JDK 8 為例:

名稱 加載哪的類 說明
Bootstrap ClassLoader(啟動類加載器) JAVA_HOME/jre/lib 無法直接訪問
Extension ClassLoader(擴(kuò)展類加載器) JAVA_HOME/jre/lib/ext 上級為 Bootstrap,顯示為 null
Application ClassLoader(應(yīng)用程序類加載器) classpath 上級為 Extension
自定義類加載器 自定義 上級為 Application

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

  • **啟動類加載器(Bootstrap ClassLoader):**這個類加載器負(fù)責(zé)將存放在 JAVA_HOME/jre/lib 目錄中的,或者被-Xbootclasspath 參數(shù)所指定的路徑中的,并且是虛擬機(jī)識別的(僅按照文件名識別,如rt.jar,名字不符合的類庫即使放在lib目錄中也不會被加載)類庫加載到虛擬機(jī)內(nèi)存中。
  • **擴(kuò)展類加載器(Extension ClassLoader):**這個加載器由 sun.misc.Launcher$ExtClassLoader 實(shí)現(xiàn),它負(fù)責(zé)加載JAVA_HOME/jre/lib/ext目錄中的,或者被 java.ext.dirs 系統(tǒng)變量所指定的路徑中的所有類庫,開發(fā)者可以直接使用擴(kuò)展類加載器。
  • **應(yīng)用程序類加載器(Application ClassLoader):**這個類加載器由 sun.misc.Launcher$AppClassLoader 實(shí)現(xiàn)。由于這個類加載器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也稱它為系統(tǒng)類加載器。它負(fù)責(zé)加載用戶類路徑(ClassPath)上所指定的類庫,開發(fā)者可以直接使用這個類加載器,如果應(yīng)用程序中沒有自定義過自己的類加載器,一般情況下這個就是程序中默認(rèn)的類加載器。
  • **自定義類加載器:**用戶自定義的類加載器。

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

類加載的過程包括:加載、驗(yàn)證、準(zhǔn)備、解析、初始化。其中驗(yàn)證、準(zhǔn)備、解析統(tǒng)稱為連接。

  • 加載:通過一個類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流,在內(nèi)存中生成一個代表這個類的java.lang.Class對象。
  • 驗(yàn)證:確保 Class 文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求,并且不會危害虛擬機(jī)自身的安全。
  • 準(zhǔn)備:為靜態(tài)變量分配內(nèi)存并設(shè)置靜態(tài)變量初始值,這里所說的初始值“通常情況”下是數(shù)據(jù)類型的零值。
  • 解析:將常量池內(nèi)的符號引用替換為直接引用。
  • 初始化:到了初始化階段,才真正開始執(zhí)行類中定義的 Java 初始化程序代碼。主要是靜態(tài)變量賦值動作和靜態(tài)語句塊(static{})中的語句。

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

如圖所示:

在這里插入圖片描述

什么是雙親委派模型?

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

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

避免重復(fù)加載 + 避免核心類篡改

  • 采用雙親委派模式的是好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系,通過這種層級關(guān)可以避免類的重復(fù)加載,當(dāng)父加載器已經(jīng)加載了該類時,就沒有必要子加載器再加載一次。
  • 其次是考慮到安全因素,java 核心 api 中定義類型不會被隨意替換,假設(shè)通過網(wǎng)絡(luò)傳遞一個名為 java.lang.Integer 的類,通過雙親委托模式傳遞到啟動類加載器,而啟動類加載器在核心Java API發(fā)現(xiàn)這個名字的類,發(fā)現(xiàn)該類已被加載,并不會重新加載網(wǎng)絡(luò)傳遞的過來的 java.lang.Integer,而直接返回已加載過的 Integer.class,這樣便可以防止核心API庫被隨意篡改。

10、說一下虛擬機(jī)棧和堆的區(qū)別?

① 物理地址方面的區(qū)別:

  • 的物理地址分配對對象是不連續(xù)的。因此性能慢些。
  • 虛擬機(jī)棧 使用的是數(shù)據(jù)結(jié)構(gòu)中的棧,先進(jìn)后出的原則,物理地址分配是連續(xù)的。所以性能快。

② 內(nèi)存分配方面的區(qū)別:

  • 因?yàn)槭遣贿B續(xù)的,所以分配的內(nèi)存是在運(yùn)行期確認(rèn)的,因此大小不固定。一般堆大小遠(yuǎn)遠(yuǎn)大于虛擬機(jī)棧。
  • 虛擬機(jī)棧 是連續(xù)的,所以分配的內(nèi)存大小要在編譯期就確認(rèn),大小是固定的。

③ 存放的內(nèi)容方面的區(qū)別:

  • 存放的是對象的實(shí)例和數(shù)組。因此該區(qū)更關(guān)注的是數(shù)據(jù)的存儲。
  • 虛擬機(jī)棧 存放的是局部變量,操作數(shù)棧,返回結(jié)果。該區(qū)更關(guān)注的是程序方法的執(zhí)行。

注:靜態(tài)變量放在方法區(qū),而靜態(tài)的對象還是放在堆。

④ 線程共享方面的區(qū)別:

  • 對于整個應(yīng)用程序都是共享、可見的。
  • 虛擬機(jī)棧 只對于線程是可見的。所以也是線程私有。他的生命周期和線程相同。

總結(jié)

文章會不定時更新,有時候一天多更新幾篇,如果幫助您復(fù)習(xí)鞏固了知識點(diǎn),后續(xù)會億點(diǎn)點(diǎn)的更新!也希望大家關(guān)注腳本之家其他文章!

相關(guān)文章

  • Spring IOC創(chuàng)建對象的兩種方式

    Spring IOC創(chuàng)建對象的兩種方式

    這篇文章主要給大家介紹了關(guān)于Spring IOC創(chuàng)建對象的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • SpringBoot詳細(xì)講解視圖整合引擎thymeleaf

    SpringBoot詳細(xì)講解視圖整合引擎thymeleaf

    這篇文章主要分享了Spring Boot整合使用Thymeleaf,Thymeleaf是新一代的Java模板引擎,類似于Velocity、FreeMarker等傳統(tǒng)引擎,關(guān)于其更多相關(guān)內(nèi)容,需要的小伙伴可以參考一下
    2022-06-06
  • Java引用傳遞和值傳遞棧內(nèi)存與堆內(nèi)存的指向操作

    Java引用傳遞和值傳遞棧內(nèi)存與堆內(nèi)存的指向操作

    這篇文章主要介紹了Java引用傳遞和值傳遞棧內(nèi)存與堆內(nèi)存的指向操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 詳解Spring Cloud Gateway 限流操作

    詳解Spring Cloud Gateway 限流操作

    這篇文章主要介紹了詳解Spring Cloud Gateway 限流操作,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Springboot配置security basic path無效解決方案

    Springboot配置security basic path無效解決方案

    這篇文章主要介紹了Springboot配置security basic path無效解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • IDEA 自定義方法注解模板的實(shí)現(xiàn)方法

    IDEA 自定義方法注解模板的實(shí)現(xiàn)方法

    這篇文章主要介紹了IDEA 自定義方法注解模板的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java throw和throws使用區(qū)別分析

    Java throw和throws使用區(qū)別分析

    這篇文章主要介紹了Java throw和throws使用區(qū)別分析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • springboot相關(guān)面試題匯總詳解

    springboot相關(guān)面試題匯總詳解

    這篇文章主要介紹了springboot相關(guān)面試題匯總詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • Java實(shí)現(xiàn)無向圖的示例詳解

    Java實(shí)現(xiàn)無向圖的示例詳解

    邊沒有方向的圖稱為無向圖,直觀來說,若一個圖中每條邊都是無方向的,則稱為無向圖。本文將通過示例詳細(xì)講解Java如何實(shí)現(xiàn)無向圖,需要的可以參考一下
    2022-04-04
  • Java圖形界面之JFrame,JLabel,JButton詳解

    Java圖形界面之JFrame,JLabel,JButton詳解

    這篇文章主要介紹了Java圖形界面之JFrame、JLabel、JButton詳解,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04

最新評論