中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

網(wǎng)站開發(fā)ide淘寶客推廣一天80單

網(wǎng)站開發(fā)ide,淘寶客推廣一天80單,成都網(wǎng)頁設(shè)計,wordpress自動評論王第一部分:JVM 概述 1.1 JVM 簡介 Java Virtual Machine(JVM) 是 Java 語言的核心組件,負(fù)責(zé)將 Java 程序編譯后的字節(jié)碼(bytecode)轉(zhuǎn)換為機(jī)器指令,并在目標(biāo)機(jī)器上執(zhí)行。JVM 提供了硬件和操作系…

第一部分:JVM 概述

1.1 JVM 簡介

Java Virtual Machine(JVM) 是 Java 語言的核心組件,負(fù)責(zé)將 Java 程序編譯后的字節(jié)碼(bytecode)轉(zhuǎn)換為機(jī)器指令,并在目標(biāo)機(jī)器上執(zhí)行。JVM 提供了硬件和操作系統(tǒng)的抽象,使得 Java 程序具有跨平臺的特性,即“一次編寫,隨處運行”(Write Once, Run Anywhere)。

JVM 的核心作用:

  • 字節(jié)碼執(zhí)行:JVM 負(fù)責(zé)執(zhí)行 Java 編譯器生成的字節(jié)碼文件(.class 文件)。
  • 內(nèi)存管理:JVM 提供自動的內(nèi)存管理機(jī)制,通過垃圾回收(Garbage Collection, GC)回收無用對象,避免了內(nèi)存泄漏。
  • 線程管理:JVM 為 Java 提供了多線程支持,管理線程的生命周期。
  • 安全機(jī)制:JVM 提供了類加載器和安全管理器,確保執(zhí)行環(huán)境的安全性。

JVM 的跨平臺性:
Java 程序的跨平臺性是通過 JVM 實現(xiàn)的。每種操作系統(tǒng)和硬件架構(gòu)都對應(yīng)不同的 JVM 實現(xiàn),Java 源代碼被編譯成字節(jié)碼后,由對應(yīng)平臺的 JVM 執(zhí)行,確保程序無需修改就能在不同平臺上運行。

1.2 JVM 運行原理簡述

JVM 的工作流程大致分為以下幾個步驟:

  1. 編譯:Java 源代碼(.java 文件)通過 Java 編譯器(javac)編譯為字節(jié)碼文件(.class 文件)。
  2. 類加載:JVM 的類加載器將字節(jié)碼文件加載到內(nèi)存,并進(jìn)行必要的驗證和準(zhǔn)備工作。
  3. 字節(jié)碼執(zhí)行:JVM 執(zhí)行字節(jié)碼文件,將其轉(zhuǎn)換為對應(yīng)平臺的機(jī)器碼,并通過解釋器或即時編譯器(JIT)執(zhí)行。
  4. 內(nèi)存管理和垃圾回收:JVM 在執(zhí)行過程中自動管理內(nèi)存分配,定期通過垃圾回收器回收不再使用的對象。
  5. 線程調(diào)度和并發(fā)控制:JVM 提供多線程支持,調(diào)度和管理 Java 線程的執(zhí)行。
1.3 JVM 與 JRE、JDK 的關(guān)系

Java 開發(fā)環(huán)境中常常提到三個重要的組成部分:JDK、JRE 和 JVM。

  1. JVM(Java Virtual Machine):

    • JVM 是 Java 程序的運行環(huán)境,負(fù)責(zé)執(zhí)行字節(jié)碼文件。它是一種虛擬機(jī),專門為 Java 設(shè)計。
  2. JRE(Java Runtime Environment):

    • JRE 是 Java 程序的運行時環(huán)境,它包含了 JVM 以及 Java 標(biāo)準(zhǔn)類庫(如 Java 核心庫、用戶界面庫等)。簡單來說,JRE 是 Java 程序運行所必需的環(huán)境,但不包含開發(fā)工具。
  3. JDK(Java Development Kit):

    • JDK 是 Java 的開發(fā)工具包,包含了開發(fā)和調(diào)試 Java 程序所需要的工具(如編譯器 javac、打包工具 jar 等)以及 JRE。因此,JDK 是開發(fā)者所使用的完整工具包,而 JRE 則是專用于運行 Java 程序的環(huán)境。

關(guān)系圖

JDK├── JRE│    ├── JVM│    └── Java 核心類庫└── 開發(fā)工具(javac、jar 等)

1.4 面試常見問題:
  1. 什么是 JVM,它的作用是什么?

    • JVM 是 Java 虛擬機(jī),負(fù)責(zé)執(zhí)行 Java 字節(jié)碼文件、管理內(nèi)存、處理線程調(diào)度等。
  2. JVM、JRE 和 JDK 之間的區(qū)別是什么?

    • JVM 是虛擬機(jī),用于執(zhí)行字節(jié)碼;JRE 是包含 JVM 和標(biāo)準(zhǔn)類庫的運行環(huán)境;JDK 是包含開發(fā)工具和 JRE 的完整開發(fā)包。
  3. JVM 如何實現(xiàn)跨平臺?

    • Java 程序通過編譯生成字節(jié)碼,JVM 將字節(jié)碼轉(zhuǎn)換為對應(yīng)平臺的機(jī)器碼,每個平臺都有其對應(yīng)的 JVM 實現(xiàn),因此實現(xiàn)了跨平臺性。
1.5 JVM 結(jié)構(gòu)

JVM 的內(nèi)部結(jié)構(gòu)復(fù)雜且精妙,由多個模塊組成,各模塊協(xié)同工作,保證 Java 程序的高效執(zhí)行。理解 JVM 的結(jié)構(gòu)可以幫助我們在面試中更好地回答性能調(diào)優(yōu)、類加載等相關(guān)問題。

JVM 的核心結(jié)構(gòu)可以劃分為以下幾個模塊:

  1. 類加載器(Class Loader)

    • 負(fù)責(zé)將字節(jié)碼文件(.class 文件)加載到 JVM 內(nèi)存中。
    • 類加載器使用了一種叫做 雙親委派模型 的機(jī)制來保證類的加載順序(將在后續(xù)章節(jié)詳細(xì)介紹)。
    • 類加載器的作用是將外部的類文件讀取進(jìn)內(nèi)存,同時對類文件進(jìn)行校驗、解析、準(zhǔn)備和初始化。
  2. 運行時數(shù)據(jù)區(qū)(Runtime Data Areas)

    • JVM 在執(zhí)行 Java 程序時,會將數(shù)據(jù)存儲在不同的內(nèi)存區(qū)域。運行時數(shù)據(jù)區(qū)可以大致分為以下幾個部分:
      • 方法區(qū)(Method Area):存儲已加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼等,屬于線程共享的內(nèi)存區(qū)。
      • 堆(Heap):存儲對象實例和數(shù)組,所有線程共享的內(nèi)存區(qū),堆是垃圾回收(GC)的重點區(qū)域。
      • 虛擬機(jī)棧(JVM Stack):每個線程都會創(chuàng)建一個虛擬機(jī)棧,用于存儲局部變量、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每個方法在執(zhí)行時都會創(chuàng)建一個棧幀(Stack Frame)。
      • 程序計數(shù)器(Program Counter Register):每個線程都有一個獨立的程序計數(shù)器,記錄當(dāng)前線程執(zhí)行的字節(jié)碼指令的地址。
      • 本地方法棧(Native Method Stack):與 JVM Stack 類似,但用于存儲本地方法調(diào)用時的相關(guān)信息。
  3. 執(zhí)行引擎(Execution Engine)

    • JVM 的執(zhí)行引擎負(fù)責(zé)解釋并執(zhí)行字節(jié)碼文件。它分為兩種執(zhí)行模式:
      • 解釋執(zhí)行:逐行解釋字節(jié)碼并執(zhí)行。
      • 即時編譯執(zhí)行(Just-In-Time, JIT):將熱點代碼編譯為機(jī)器碼,直接在 CPU 上執(zhí)行以提高性能。
    • JVM 還會利用多種優(yōu)化技術(shù),如內(nèi)聯(lián)、逃逸分析等,來提升代碼執(zhí)行效率(將在后續(xù)章節(jié)詳細(xì)講解)。
  4. 本地方法接口(JNI,Java Native Interface)

    • JVM 通過 JNI 提供調(diào)用非 Java 代碼的能力,例如調(diào)用 C/C++ 編寫的底層代碼或操作系統(tǒng)原生方法。
    • JNI 的作用是幫助 JVM 擴(kuò)展與底層系統(tǒng)的交互功能,尤其是在需要調(diào)用特定硬件或者優(yōu)化性能時。
  5. 垃圾回收器(Garbage Collector)

    • JVM 提供自動內(nèi)存管理機(jī)制,垃圾回收器負(fù)責(zé)回收不再被引用的對象,防止內(nèi)存泄漏。
    • 垃圾回收器通過不同的算法(如標(biāo)記-清除、標(biāo)記-整理、分代收集等)和回收器(如 Serial、CMS、G1 等)執(zhí)行垃圾回收。
1.6 面試常見問題:
  1. JVM 的核心組成部分有哪些?

    • JVM 包含類加載器、運行時數(shù)據(jù)區(qū)、執(zhí)行引擎、本地方法接口、垃圾回收器等核心模塊。
  2. JVM 的運行時數(shù)據(jù)區(qū)是如何劃分的?

    • JVM 的內(nèi)存模型分為方法區(qū)、堆、虛擬機(jī)棧、程序計數(shù)器和本地方法棧,每個區(qū)域有不同的用途和生命周期。
  3. 執(zhí)行引擎中解釋器與即時編譯器(JIT)的區(qū)別是什么?

    • 解釋器逐行解釋字節(jié)碼并執(zhí)行,而 JIT 編譯器將熱點代碼編譯為機(jī)器碼直接執(zhí)行,以提高性能。
  4. 什么是 JNI(Java Native Interface),它的作用是什么?

    • JNI 是 Java 與其他編程語言(如 C/C++)交互的接口,允許 Java 程序調(diào)用本地代碼和系統(tǒng) API。

第二部分:JVM 內(nèi)存模型

2.1 JVM 內(nèi)存區(qū)域劃分

JVM 在運行時將內(nèi)存劃分為多個區(qū)域,每個區(qū)域負(fù)責(zé)不同的任務(wù),合理的內(nèi)存劃分幫助 JVM 高效地管理應(yīng)用程序的資源。JVM 的內(nèi)存模型大致可以分為以下幾個部分:

  1. 方法區(qū)(Method Area)

    • 作用:方法區(qū)存儲已加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼等。
    • 特點
      • 屬于線程共享的區(qū)域,每個線程都可以訪問方法區(qū)。
      • 方法區(qū)中還包含了運行時常量池(Runtime Constant Pool),用于存儲編譯期生成的各種字面量和符號引用。
      • 方法區(qū)在 JVM 規(guī)范中是邏輯上的概念,在不同的 JVM 實現(xiàn)中可能會有所差異。在 HotSpot 虛擬機(jī)中,方法區(qū)被稱為“永久代(Permanent Generation)”,但在 Java 8 中,永久代被元空間(Metaspace)取代。
  2. 堆(Heap)

    • 作用:堆是 JVM 中用于存儲對象實例的區(qū)域,幾乎所有的對象實例和數(shù)組都存儲在堆中。
    • 特點
      • 堆是所有線程共享的內(nèi)存區(qū)域,是垃圾回收的重點區(qū)域。
      • Java 堆在邏輯上分為新生代(Young Generation)和老年代(Old Generation)。新生代進(jìn)一步劃分為 Eden 區(qū)和兩個 Survivor 區(qū)(S0 和 S1),用于存儲新創(chuàng)建的對象。
      • 堆內(nèi)存大小可以通過 -Xms-Xmx 參數(shù)進(jìn)行設(shè)置,-Xms 指定堆的初始大小,-Xmx 指定堆的最大大小。
  3. 虛擬機(jī)棧(JVM Stack)

    • 作用:每個線程在執(zhí)行 Java 方法時都會創(chuàng)建一個棧幀,用于存儲局部變量、操作數(shù)棧、動態(tài)鏈接、方法出口等信息,虛擬機(jī)棧是這些棧幀的集合。
    • 特點
      • 每個線程都有自己獨立的虛擬機(jī)棧,線程執(zhí)行時,棧幀按照方法調(diào)用順序進(jìn)棧、出棧。
      • 如果線程請求的棧深度大于虛擬機(jī)棧的最大深度,會拋出 StackOverflowError
      • 如果虛擬機(jī)棧無法申請到足夠內(nèi)存時,會拋出 OutOfMemoryError
  4. 程序計數(shù)器(Program Counter Register)

    • 作用:程序計數(shù)器是一個較小的內(nèi)存區(qū)域,用于存儲當(dāng)前線程所執(zhí)行的字節(jié)碼指令的地址。
    • 特點
      • 每個線程都有獨立的程序計數(shù)器,用于記錄該線程下一條要執(zhí)行的字節(jié)碼指令位置。
      • 如果線程執(zhí)行的是本地方法,程序計數(shù)器的值為空(Undefined)。
      • 程序計數(shù)器是 JVM 中唯一不會發(fā)生內(nèi)存溢出的區(qū)域。
  5. 本地方法棧(Native Method Stack)

    • 作用:本地方法棧用于存儲每個線程執(zhí)行的本地方法的相關(guān)信息,類似于虛擬機(jī)棧,但它為本地方法(Native 方法)服務(wù)。
    • 特點
      • 本地方法棧為 Java 調(diào)用 C/C++ 等本地方法時提供了支持。
      • 與虛擬機(jī)棧類似,本地方法棧在某些情況下也可能拋出 StackOverflowErrorOutOfMemoryError
2.2 運行時常量池

運行時常量池(Runtime Constant Pool) 是方法區(qū)的一部分,用于存儲編譯期生成的常量,如字符串常量、數(shù)值常量等,以及類、方法的符號引用。

特點

  • 動態(tài)性:與 Class 文件中的常量池不同,運行時常量池支持動態(tài)添加常量。例如,運行時通過 String.intern() 方法將字符串放入常量池。
  • 內(nèi)存溢出:當(dāng)常量池?zé)o法申請到足夠內(nèi)存時,也會拋出 OutOfMemoryError。
2.3 Java 內(nèi)存模型(JMM)

Java 內(nèi)存模型(Java Memory Model, JMM)定義了 Java 程序中多線程操作的內(nèi)存可見性規(guī)則,確保不同線程之間對共享變量的讀寫操作有序可見。

  1. 可見性

    • 當(dāng)一個線程對共享變量進(jìn)行了修改,其他線程應(yīng)該立即看到修改結(jié)果。
    • volatile 關(guān)鍵字可以確保變量的可見性,強(qiáng)制將修改后的變量值同步到主內(nèi)存。
  2. 有序性

    • Java 程序中的操作可能會因為編譯器優(yōu)化或 CPU 的亂序執(zhí)行而導(dǎo)致執(zhí)行順序與代碼順序不同。
    • synchronizedvolatile 關(guān)鍵字可以確保操作的有序性。
  3. 原子性

    • 原子性意味著一個操作是不可分割的,中間不會被打斷。
    • Java 的基本數(shù)據(jù)類型賦值是原子操作,longdouble 類型的賦值在 32 位 JVM 中不是原子的。synchronizedLock 可以確保多線程情況下的原子性操作。
2.4 面試常見問題:
  1. JVM 中堆與棧的區(qū)別是什么?

    • 堆是存儲對象實例的區(qū)域,屬于線程共享的內(nèi)存;棧是線程私有的內(nèi)存區(qū)域,用于存儲局部變量、方法調(diào)用信息。
  2. 程序計數(shù)器的作用是什么?

    • 程序計數(shù)器記錄當(dāng)前線程正在執(zhí)行的字節(jié)碼指令的地址,確保線程切換后能正確恢復(fù)執(zhí)行。
  3. JVM 內(nèi)存劃分的區(qū)域有哪些?

    • JVM 運行時內(nèi)存劃分為方法區(qū)、堆、虛擬機(jī)棧、程序計數(shù)器和本地方法棧,每個區(qū)域有不同的職責(zé)。
  4. 什么是 Java 內(nèi)存模型(JMM),它解決了什么問題?

    • JMM 規(guī)定了 Java 程序中多線程操作共享變量時的可見性、有序性和原子性,確保線程安全。

第三部分:類加載機(jī)制

3.1 類加載過程

類加載機(jī)制是 JVM 的核心之一,它負(fù)責(zé)將類從字節(jié)碼文件加載到內(nèi)存并準(zhǔn)備執(zhí)行。類加載過程主要分為以下五個階段:

  1. 加載(Loading)

    • 通過類的全限定名來獲取該類的字節(jié)碼內(nèi)容,并將其轉(zhuǎn)換成 JVM 可以識別的類對象(java.lang.Class)。
    • 在加載過程中,JVM 會根據(jù)類的全限定名找到對應(yīng)的字節(jié)碼文件(通常是 .class 文件),然后通過類加載器(ClassLoader)加載到內(nèi)存中。
  2. 驗證(Verification)

    • 確保字節(jié)碼文件的正確性和安全性,防止惡意代碼損害 JVM 的運行。
    • 驗證的過程包括文件格式驗證、元數(shù)據(jù)驗證、字節(jié)碼驗證和符號引用驗證。例如,它會確保類文件的格式正確、沒有非法的操作碼等。
  3. 準(zhǔn)備(Preparation)

    • 為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值(如 0、null)。
    • 這一步不會給變量賦值實際的值,只會分配內(nèi)存空間并初始化為默認(rèn)值,真正的賦值操作會在初始化階段完成。
  4. 解析(Resolution)

    • 將常量池中的符號引用(Symbolic Reference)替換為直接引用(Direct Reference)。
    • 解析的目標(biāo)是將常量池中的符號引用轉(zhuǎn)化為內(nèi)存地址,如類、字段、方法等引用都會在解析階段被轉(zhuǎn)換為實際的內(nèi)存地址。
  5. 初始化(Initialization)

    • 執(zhí)行類的靜態(tài)代碼塊(<clinit> 方法)和靜態(tài)變量的初始化。
    • 在這個階段,類的靜態(tài)變量會被賦值為程序員指定的值,執(zhí)行順序依照代碼中的靜態(tài)代碼塊和靜態(tài)變量聲明順序。
3.2 類加載器

JVM 使用類加載器(ClassLoader)來加載類的字節(jié)碼文件。每個類在 JVM 中都有且只有一個類加載器負(fù)責(zé)加載它。Java 提供了多種類加載器,每種類加載器負(fù)責(zé)加載不同的類。

  1. 啟動類加載器(Bootstrap ClassLoader)

    • 作用:啟動類加載器是 JVM 內(nèi)置的,用于加載核心類庫(如 java.lang.*java.util.* 等),這些類庫存放在 JRE/lib 目錄下。
    • 特點:啟動類加載器是由本地代碼實現(xiàn)的,它加載的是 JVM 啟動時所需的核心類,并且不繼承自 ClassLoader 類。
  2. 擴(kuò)展類加載器(Extension ClassLoader)

    • 作用:擴(kuò)展類加載器加載的是 JRE/lib/ext 目錄中的類或通過 java.ext.dirs 系統(tǒng)變量指定的類庫。
    • 特點:它是 ClassLoader 的子類,由 Java 編寫,主要加載一些擴(kuò)展類庫。
  3. 應(yīng)用程序類加載器(Application ClassLoader)

    • 作用:也稱為系統(tǒng)類加載器,負(fù)責(zé)加載用戶類路徑(classpath)下的類,幾乎所有應(yīng)用程序中的類都是由它加載的。
    • 特點:它是 ClassLoader 類的實例,可以通過 ClassLoader.getSystemClassLoader() 方法獲取。
  4. 自定義類加載器(Custom ClassLoader)

    • 作用:開發(fā)者可以通過繼承 ClassLoader 類實現(xiàn)自己的類加載器,以滿足特殊需求,比如動態(tài)加載類、網(wǎng)絡(luò)加載類等。
    • 特點:自定義類加載器允許開發(fā)者通過覆蓋 findClass() 方法來自定義類的加載方式。
3.3 雙親委派機(jī)制

雙親委派模型是 JVM 類加載機(jī)制中的一個重要原則,它規(guī)定當(dāng)類加載器加載某個類時,首先會將請求委派給父類加載器,父類加載器繼續(xù)向上委派,直到頂層的啟動類加載器。如果父類加載器無法加載該類,才會由當(dāng)前加載器嘗試加載。

雙親委派機(jī)制的優(yōu)點

  1. 避免重復(fù)加載:通過雙親委派機(jī)制,確保 Java 核心類庫不會被重復(fù)加載。
  2. 安全性:防止自定義類加載器加載替代 Java 核心類的類,比如 java.lang.String 類,確保系統(tǒng)安全。

打破雙親委派模型

  • 在某些場景下,雙親委派模型需要被打破,例如通過自定義類加載器動態(tài)加載某些類。常見的例子是 Java 的 SPI 機(jī)制(Service Provider Interface),這需要使用 Thread.getContextClassLoader() 來加載自定義類。
3.4 面試常見問題:
  1. 類加載的五個階段分別是什么?

    • 加載、驗證、準(zhǔn)備、解析、初始化。
  2. 雙親委派模型的作用是什么?

    • 雙親委派模型確保類的加載遵循先父后子的原則,避免核心類庫被重復(fù)加載或篡改。
  3. 自定義類加載器有什么應(yīng)用場景?

    • 自定義類加載器適用于動態(tài)加載類、模塊化加載等場景,如 OSGi 模塊化系統(tǒng)和熱部署等。

第四部分:JVM 垃圾回收

4.1 垃圾回收概述

JVM 提供了自動內(nèi)存管理機(jī)制,通過垃圾回收器(GC)來釋放不再使用的對象,避免內(nèi)存泄漏。垃圾回收的主要目標(biāo)是回收堆內(nèi)存中那些不可達(dá)的對象。

垃圾回收的必要性

  • 手動管理內(nèi)存容易導(dǎo)致內(nèi)存泄漏或內(nèi)存溢出,而 JVM 自動管理對象生命周期,減少了程序員的負(fù)擔(dān)。
  • 在沒有垃圾回收的情況下,程序員需要手動釋放內(nèi)存,增加了開發(fā)復(fù)雜度和出錯幾率。

內(nèi)存泄漏與內(nèi)存溢出

  • 內(nèi)存泄漏:指對象不會再被程序使用,但由于存在引用,導(dǎo)致它無法被垃圾回收器回收。
  • 內(nèi)存溢出(OutOfMemoryError):指 JVM 在運行時無法分配足夠的內(nèi)存,通常是堆或方法區(qū)無法申請到足夠內(nèi)存空間。
4.2 垃圾回收算法

垃圾回收器使用不同的算法來識別和回收不再需要的對象,常見的垃圾回收算法有以下幾種:

  1. 標(biāo)記-清除算法(Mark-Sweep)

    • 過程:首先標(biāo)記出所有需要回收的對象,然后直接清除它們。
    • 優(yōu)點:實現(xiàn)簡單,不需要額外的內(nèi)存空間。
    • 缺點:標(biāo)記和清除過程效率低,并且會產(chǎn)生大量內(nèi)存碎片。
  2. 復(fù)制算法(Copying)

    • 過程:將存活的對象從當(dāng)前內(nèi)存區(qū)域復(fù)制到另一個區(qū)域,然后清空當(dāng)前區(qū)域。
    • 優(yōu)點:復(fù)制算法可以避免內(nèi)存碎片問題,分配內(nèi)存高效。
    • 缺點:需要額外的內(nèi)存空間進(jìn)行對象復(fù)制。
  3. 標(biāo)記-整理算法(Mark-Compact)

    • 過程:首先標(biāo)記出所有存活的對象,然后將存活對象壓縮到內(nèi)存的一端,最后清理掉未使用的內(nèi)存空間。
    • 優(yōu)點:避免了內(nèi)存碎片問題,不需要額外的內(nèi)存空間。
    • 缺點:移動存活對象的成本較高,適合老年代回收。
  4. 分代收集算法(Generational Garbage Collection)

    • 過程:將堆內(nèi)存劃分為新生代和老年代,不同代的對象使用不同的垃圾回收算法。
    • 優(yōu)點:適應(yīng)對象的生命周期特點,新生代回收頻繁,老年代回收較少。
    • 缺點:新生代和老年代的垃圾回收算法不同,增加了系統(tǒng)的復(fù)雜度。
4.3 垃圾回收器

垃圾回收器是具體執(zhí)行垃圾回收的組件,常見的垃圾回收器有:

  1. Serial 垃圾回收器

    • 單線程垃圾回收器,適用于單線程環(huán)境或內(nèi)存較小的客戶端應(yīng)用。
  2. Parallel 垃圾回收器

    • 多線程垃圾回收器,適用于多核 CPU,可以在多個 CPU 上并行執(zhí)行垃圾回收操作。
  3. CMS(Concurrent Mark-Sweep)垃圾回收器

    • 低停頓垃圾回收器,使用標(biāo)記-清除算法,在應(yīng)用運行過程中并發(fā)執(zhí)行垃圾回收,適用于需要較短停頓時間的應(yīng)用。
  4. G1(Garbage-First)垃圾回收器

    • 面向服務(wù)端應(yīng)用的低停頓垃圾回收器,適用于大堆內(nèi)存,能夠同時處理新生代和老年代的垃圾回收,避免 Full GC。

第五部分:JVM 性能調(diào)優(yōu)

5.1 常用 JVM 參數(shù)

JVM 提供了一系列參數(shù),用于控制內(nèi)存大小、垃圾回收行為、性能調(diào)優(yōu)等。合理配置 JVM 參數(shù)能夠顯著提升 Java 應(yīng)用的運行效率。以下是一些常用的 JVM 參數(shù):

  1. 堆內(nèi)存大小設(shè)置

    • -Xms:設(shè)置堆內(nèi)存的初始大小。例如,-Xms512m 表示 JVM 啟動時堆內(nèi)存大小為 512MB。
    • -Xmx:設(shè)置堆內(nèi)存的最大大小。例如,-Xmx1024m 表示 JVM 堆內(nèi)存最大可達(dá)到 1024MB。
    • 調(diào)優(yōu)建議:將 -Xms-Xmx 設(shè)置為相同的值,可以避免 JVM 在運行過程中頻繁調(diào)整堆內(nèi)存大小,從而減少性能波動。
  2. 棧內(nèi)存大小設(shè)置

    • -Xss:設(shè)置每個線程的棧內(nèi)存大小。例如,-Xss512k 表示每個線程的棧內(nèi)存大小為 512KB。
    • 調(diào)優(yōu)建議:對于多線程應(yīng)用,適當(dāng)增加棧內(nèi)存大小可以避免棧溢出(StackOverflowError),但過大的棧內(nèi)存會消耗更多的物理內(nèi)存。
  3. 垃圾回收器選擇

    • -XX:+UseSerialGC:使用 Serial 垃圾回收器,適用于單線程應(yīng)用或資源受限的環(huán)境。
    • -XX:+UseParallelGC:使用 Parallel 垃圾回收器,適用于高吞吐量、多核 CPU 環(huán)境。
    • -XX:+UseConcMarkSweepGC:使用 CMS 垃圾回收器,適用于對低停頓時間有要求的場景。
    • -XX:+UseG1GC:使用 G1 垃圾回收器,適用于大堆內(nèi)存的低延遲應(yīng)用。
    • 調(diào)優(yōu)建議:選擇合適的垃圾回收器取決于應(yīng)用的特點,CMS 和 G1 更適合低延遲應(yīng)用,而 Parallel 更適合高吞吐量的服務(wù)端應(yīng)用。
  4. 永久代/元空間設(shè)置

    • -XX:PermSize:設(shè)置永久代的初始大小(適用于 Java 7 及以下版本)。
    • -XX:MaxPermSize:設(shè)置永久代的最大大小(適用于 Java 7 及以下版本)。
    • -XX:MetaspaceSize:設(shè)置元空間的初始大小(適用于 Java 8 及以上版本)。
    • -XX:MaxMetaspaceSize:設(shè)置元空間的最大大小(適用于 Java 8 及以上版本)。
    • 調(diào)優(yōu)建議:Java 8 及以上版本采用了元空間來替代永久代,適當(dāng)設(shè)置元空間大小可以避免 OutOfMemoryError。
5.2 性能調(diào)優(yōu)工具

JVM 提供了多種性能調(diào)優(yōu)工具,用于監(jiān)控和分析 Java 應(yīng)用的運行狀態(tài),幫助開發(fā)者定位性能瓶頸。常用工具包括:

  1. jstat

    • 作用:用于監(jiān)控 JVM 運行時的內(nèi)存和垃圾回收情況。
    • 常用命令
      • jstat -gc pid:顯示 GC 相關(guān)信息。
      • jstat -gcutil pid:顯示各代內(nèi)存使用情況。
  2. jmap

    • 作用:用于生成 Java 堆的內(nèi)存快照(heap dump),并可以分析堆中對象的占用情況。
    • 常用命令
      • jmap -heap pid:查看 JVM 堆的詳細(xì)信息。
      • jmap -dump:format=b,file=heap_dump.hprof pid:生成堆快照文件。
  3. jstack

    • 作用:用于查看線程的堆棧信息,幫助分析線程死鎖、線程阻塞等問題。
    • 常用命令
      • jstack pid:輸出當(dāng)前 JVM 進(jìn)程的線程堆棧信息。
  4. jconsole

    • 作用:JDK 自帶的圖形化監(jiān)控工具,用于監(jiān)控 JVM 的內(nèi)存、線程、CPU 使用情況。
    • 特點:直觀易用,適合實時監(jiān)控應(yīng)用的運行狀態(tài)。
  5. VisualVM

    • 作用:集成了多種分析功能,包括堆快照分析、GC 日志分析、CPU 和內(nèi)存使用分析等。
    • 特點:支持實時監(jiān)控和離線分析,適合分析性能問題和內(nèi)存泄漏。
  6. MAT(Memory Analyzer Tool)

    • 作用:用于分析 Java 堆快照,幫助定位內(nèi)存泄漏、分析大對象。
    • 特點:可以深入分析大對象及其引用關(guān)系,幫助開發(fā)者找到內(nèi)存泄漏的根源。
5.3 常見性能優(yōu)化策略
  1. 減少 Full GC 觸發(fā)

    • 問題:Full GC 是垃圾回收中最耗時的一種操作,會暫停所有應(yīng)用線程,影響應(yīng)用性能。
    • 優(yōu)化策略
      • 通過 -Xms-Xmx 設(shè)置合理的堆大小,避免頻繁的內(nèi)存分配和回收。
      • 使用 G1 或 CMS 垃圾回收器,這些回收器在執(zhí)行 Full GC 時更高效。
      • 優(yōu)化代碼中對象的生命周期,避免短命對象大量創(chuàng)建和長時間存活。
  2. 內(nèi)存泄漏排查

    • 問題:內(nèi)存泄漏會導(dǎo)致應(yīng)用的堆內(nèi)存不斷增長,最終觸發(fā) OutOfMemoryError。
    • 優(yōu)化策略
      • 使用 jmap 生成堆快照,并用 MAT 分析內(nèi)存泄漏對象的引用鏈,找到泄漏源。
      • 避免全局靜態(tài)變量持有大對象引用,及時清理不再使用的對象。
      • 使用 WeakReferenceSoftReference 代替強(qiáng)引用,減少對象不必要的長時間引用。
  3. 方法區(qū)溢出優(yōu)化

    • 問題:方法區(qū)(Java 8 之前稱為永久代)可能因類或方法過多而溢出,觸發(fā) OutOfMemoryError。
    • 優(yōu)化策略
      • 使用 -XX:MaxMetaspaceSize 設(shè)置合理的元空間大小,避免方法區(qū)溢出。
      • 對于動態(tài)生成類的應(yīng)用,使用類卸載機(jī)制,及時卸載不再使用的類。
  4. 線程調(diào)優(yōu)

    • 問題:線程過多或線程資源爭用可能導(dǎo)致 CPU 利用率低或線程阻塞。
    • 優(yōu)化策略
      • 使用 jstack 分析線程狀態(tài),定位死鎖或線程饑餓問題。
      • 適當(dāng)減少線程池中線程數(shù)量,避免頻繁的上下文切換。
5.4 面試常見問題:
  1. 如何通過 JVM 參數(shù)來調(diào)優(yōu) Java 應(yīng)用的性能?

    • 可以通過調(diào)整堆大小、選擇合適的垃圾回收器、設(shè)置棧大小等參數(shù)來優(yōu)化 JVM 性能。
  2. 如何定位和解決內(nèi)存泄漏問題?

    • 使用 jmap 生成堆快照并結(jié)合 MAT 工具分析堆中的對象引用鏈,找到內(nèi)存泄漏的來源。
  3. Full GC 是什么,它的觸發(fā)原因有哪些?

    • Full GC 是對整個堆內(nèi)存(包括新生代和老年代)進(jìn)行的垃圾回收,通常由堆內(nèi)存不足、方法區(qū)滿等原因觸發(fā)。

第六部分:字節(jié)碼與執(zhí)行引擎

6.1 字節(jié)碼簡介

字節(jié)碼(Bytecode) 是一種面向虛擬機(jī)的中間語言,是 JVM 執(zhí)行 Java 程序的基礎(chǔ)。Java 源代碼經(jīng)過編譯后生成 .class 文件,其中包含了 JVM 可以理解的字節(jié)碼指令。

字節(jié)碼的特點

  • 與硬件無關(guān),跨平臺性強(qiáng)。Java 編譯器生成的字節(jié)碼可以在任何 JVM 上運行。
  • 每個字節(jié)碼指令對應(yīng)特定的操作,如加載、存儲、運算、控制跳轉(zhuǎn)等。

查看字節(jié)碼

  • 可以使用 JDK 自帶的 javap 工具查看 .class 文件中的字節(jié)碼。例如,javap -c MyClass 可以打印出 MyClass 的字節(jié)碼指令。
6.2 解釋器與即時編譯器(JIT)

JVM 執(zhí)行字節(jié)碼的方式有兩種:解釋執(zhí)行和即時編譯(JIT)。

  1. 解釋器
    • JVM 通過解釋器逐條解釋執(zhí)行字節(jié)碼。

每次遇到字節(jié)碼指令時,解釋器將其轉(zhuǎn)換為機(jī)器碼并執(zhí)行。

  • 優(yōu)點:啟動速度快,因為無需等待字節(jié)碼的編譯。
  • 缺點:解釋執(zhí)行的效率較低,尤其在執(zhí)行頻繁的代碼段時,性能會受到影響。
  1. 即時編譯器(JIT)
    • JIT 編譯器在運行時將熱點代碼(執(zhí)行頻率高的代碼)編譯為機(jī)器碼,直接在 CPU 上執(zhí)行。
    • 優(yōu)點:通過將熱點代碼編譯為機(jī)器碼,JIT 提升了程序的執(zhí)行效率。
    • 缺點:JIT 編譯需要額外的時間和資源,可能在程序啟動階段增加延遲。

JVM 的 JIT 編譯器通常分為兩個階段:

  • C1 編譯器:進(jìn)行簡單優(yōu)化,生成較快的機(jī)器碼,適合應(yīng)用啟動階段使用。
  • C2 編譯器:進(jìn)行復(fù)雜優(yōu)化,生成更高效的機(jī)器碼,適合長時間運行的熱點代碼。
6.3 逃逸分析與鎖消除
  1. 逃逸分析

    • 逃逸分析是 JIT 編譯器的優(yōu)化技術(shù),用于判斷對象的作用范圍。如果對象只在方法內(nèi)部使用而不會逃逸到方法外部,則可以將其分配在棧上而不是堆上,從而減少堆內(nèi)存分配和垃圾回收的壓力。
  2. 鎖消除

    • 鎖消除是基于逃逸分析的一種優(yōu)化技術(shù)。如果編譯器通過逃逸分析發(fā)現(xiàn)加鎖的對象不會被其他線程訪問,那么就可以消除該鎖,從而避免不必要的同步操作,提升性能。

第七部分:JVM 常見面試問題總結(jié)

7.1 JVM 高頻面試問題

在 Java 面試中,JVM 是一個非常常見的考察點。以下是一些常見的 JVM 面試問題,涵蓋 JVM 的內(nèi)存模型、垃圾回收機(jī)制、類加載器等多個方面。這些問題不僅要求面試者對 JVM 的工作原理有深刻的理解,還需要有實際調(diào)優(yōu)和問題排查的經(jīng)驗。

1. JVM 的內(nèi)存結(jié)構(gòu)是什么樣的?
  • 回答思路:
    • JVM 內(nèi)存劃分為方法區(qū)(Java 8 后稱為元空間)、堆、虛擬機(jī)棧、程序計數(shù)器、本地方法棧五個區(qū)域。
    • 堆內(nèi)存用于存儲對象實例,分為新生代和老年代。虛擬機(jī)棧保存每個線程的局部變量、操作數(shù)棧等。
    • 方法區(qū)存儲類信息、常量、靜態(tài)變量、即時編譯代碼。程序計數(shù)器記錄當(dāng)前線程的執(zhí)行位置。
2. JVM 中堆和棧的區(qū)別是什么?
  • 回答思路:
    • 堆用于存儲所有對象實例和數(shù)組,屬于線程共享區(qū)域,垃圾回收器會在堆中回收不再使用的對象。
    • 棧用于存儲線程的局部變量、方法調(diào)用鏈信息,每個線程都有自己的棧。棧內(nèi)存較小,生命周期與線程一致。
3. 你對垃圾回收機(jī)制了解多少?可以介紹一下不同的垃圾回收器嗎?
  • 回答思路:
    • 垃圾回收器通過追蹤和清除不可達(dá)對象來釋放內(nèi)存,常用的垃圾回收算法包括標(biāo)記-清除、復(fù)制、標(biāo)記-整理等。
    • 常見的垃圾回收器有 Serial、Parallel、CMS 和 G1。Serial 單線程執(zhí)行垃圾回收,Parallel 使用多線程執(zhí)行,CMS 適用于低停頓的應(yīng)用,G1 適用于大堆內(nèi)存的服務(wù)端應(yīng)用。
4. Full GC 發(fā)生的原因是什么?如何優(yōu)化避免 Full GC?
  • 回答思路:
    • Full GC 是對整個堆內(nèi)存(包括新生代和老年代)進(jìn)行的垃圾回收操作,通常由老年代內(nèi)存不足、方法區(qū)溢出等原因觸發(fā)。
    • 優(yōu)化方法包括:增大堆內(nèi)存大小,減少對象的頻繁創(chuàng)建和過長生命周期,調(diào)整垃圾回收器設(shè)置如 G1 或 CMS,合理設(shè)置元空間大小。
5. 雙親委派模型的作用是什么?有遇到過需要打破雙親委派模型的情況嗎?
  • 回答思路:
    • 雙親委派模型規(guī)定類加載請求會優(yōu)先委派給父類加載器,以保證核心類庫不會被重復(fù)加載或篡改。
    • 常見的打破雙親委派模型的場景有 SPI 機(jī)制,它需要使用線程上下文類加載器加載自定義的服務(wù)實現(xiàn)。
6. 類加載過程有哪些步驟?
  • 回答思路:
    • 類加載分為加載、驗證、準(zhǔn)備、解析、初始化五個步驟。
    • 加載階段通過類加載器將字節(jié)碼加載到內(nèi)存;驗證階段確保類的合法性;準(zhǔn)備階段為類的靜態(tài)變量分配內(nèi)存;解析階段將符號引用替換為直接引用;初始化階段執(zhí)行靜態(tài)代碼塊和靜態(tài)變量賦值。
7. 如何排查 OutOfMemoryError
  • 回答思路:
    • OutOfMemoryError 可能發(fā)生在堆、方法區(qū)或虛擬機(jī)棧中。常見原因有對象過多、類加載過多或棧深度過大。
    • 使用 jmap 生成堆快照,通過 MAT 分析內(nèi)存泄漏問題;通過 -XX:MaxMetaspaceSize 控制元空間大小;通過 -Xss 調(diào)整棧大小。
8. 什么是逃逸分析?它有什么用?
  • 回答思路:
    • 逃逸分析是 JIT 編譯器的優(yōu)化技術(shù),用于判斷對象是否逃逸出當(dāng)前方法。如果對象未逃逸,JVM 可以將其分配在棧上,避免在堆中分配對象。
    • 優(yōu)點是減少堆內(nèi)存分配和垃圾回收開銷,并且提高對象的訪問速度。
9. 什么是內(nèi)存屏障?在 JVM 中它有什么作用?
  • 回答思路:
    • 內(nèi)存屏障是一種指令,用于禁止 CPU 的指令重排序。它確保在多線程環(huán)境下,某些操作(如讀寫共享變量)具有可見性和有序性。
    • 在 JVM 中,volatile 關(guān)鍵字可以通過內(nèi)存屏障確保變量的可見性和有序性。
10. 什么是類卸載?它發(fā)生在什么情況下?
  • 回答思路:
    • 類卸載是指 JVM 從內(nèi)存中移除不再使用的類,通常在不再需要加載的類被垃圾回收器回收時發(fā)生。
    • 類卸載主要發(fā)生在自定義類加載器加載的類上,當(dāng)類加載器和其加載的類都沒有被引用時,類可以被卸載。
11. Java 8 中永久代的變化?為什么 Java 8 使用元空間代替了永久代?
  • 回答思路:
    • 在 Java 8 中,永久代被移除,取而代之的是元空間。永久代用于存儲類的元數(shù)據(jù)和靜態(tài)變量等,但容易導(dǎo)致內(nèi)存溢出。
    • 元空間不使用堆內(nèi)存,而是直接使用本地內(nèi)存,從而可以動態(tài)調(diào)整大小,避免永久代內(nèi)存溢出的情況。
12. 什么是 JVM 調(diào)優(yōu)?你有實際 JVM 調(diào)優(yōu)的經(jīng)驗嗎?
  • 回答思路:
    • JVM 調(diào)優(yōu)是通過調(diào)整 JVM 參數(shù)和配置來優(yōu)化 Java 應(yīng)用的性能。常見調(diào)優(yōu)包括堆內(nèi)存大小的調(diào)整、垃圾回收器的選擇、Full GC 頻率的控制、線程調(diào)度優(yōu)化等。
    • 實際調(diào)優(yōu)經(jīng)驗可以包括通過 GC 日志分析性能問題、使用工具(如 jmap、jstack、VisualVM)來排查內(nèi)存和線程問題,以及如何根據(jù)業(yè)務(wù)需求配置合適的 JVM 參數(shù)。
7.2 綜合性 JVM 問題場景分析
  1. 場景一:大型電商系統(tǒng)的 JVM 調(diào)優(yōu)實踐

    • 問題:系統(tǒng)在高并發(fā)情況下頻繁發(fā)生 Full GC,導(dǎo)致響應(yīng)時間延遲。
    • 分析:通過查看 GC 日志,發(fā)現(xiàn)堆內(nèi)存不足導(dǎo)致頻繁的 Full GC。通過增加堆大小(-Xms-Xmx),并使用 G1 垃圾回收器替代 CMS,減少了 Full GC 的次數(shù)。此外,減少了長生命周期對象的使用,降低了老年代的占用。
  2. 場景二:內(nèi)存泄漏問題排查

    • 問題:某線上服務(wù)隨著運行時間增長,內(nèi)存不斷增加,最終拋出 OutOfMemoryError。
    • 分析:使用 jmap 生成堆快照,通過 MAT 工具分析堆內(nèi)存,發(fā)現(xiàn)某個靜態(tài)集合類沒有清理不再使用的對象,導(dǎo)致了內(nèi)存泄漏。解決方案是在代碼中定期清理該集合,釋放不再需要的對象。
  3. 場景三:多線程應(yīng)用的 JVM 棧溢出

    • 問題:在處理復(fù)雜業(yè)務(wù)邏輯時,系統(tǒng)拋出 StackOverflowError。
    • 分析:由于業(yè)務(wù)邏輯存在深度遞歸調(diào)用,導(dǎo)致棧深度超出默認(rèn)值。通過調(diào)整 JVM 棧大小參數(shù)(-Xss),增加每個線程的??臻g,解決了棧溢出問題。
7.3 常見陷阱與誤區(qū)
  1. 誤區(qū)一:JVM 參數(shù)設(shè)置越大越好

    • 解釋:并不是堆內(nèi)存、棧內(nèi)存設(shè)置得越大越好。過大的堆會導(dǎo)致垃圾回收耗時較長,棧內(nèi)存設(shè)置過大則可能浪費系統(tǒng)資源,甚至引發(fā)系統(tǒng)崩潰。應(yīng)根據(jù)應(yīng)用實際需求來設(shè)置合理的 JVM 參數(shù)。
  2. 誤區(qū)二:Full GC 觸發(fā)時 JVM 會立即回收所有對象

    • 解釋:Full GC 是回收整個堆內(nèi)存,但并不能保證所有對象都被立即回收。如果對象之間存在復(fù)雜的引用鏈,或者引用關(guān)系沒有正確處理,可能導(dǎo)致對象仍然存活。
  3. 誤區(qū)三:永久代溢出等同于堆內(nèi)存溢出

    • 解釋:永久代溢出和堆內(nèi)存溢出是兩

種不同的錯誤。永久代溢出與類的元數(shù)據(jù)、靜態(tài)變量等有關(guān),堆內(nèi)存溢出則是由于對象實例數(shù)量過多導(dǎo)致堆空間不足。在 Java 8 之后,永久代已被元空間替代。
在這里插入圖片描述

http://www.risenshineclean.com/news/9093.html

相關(guān)文章:

  • dreamwearver可以做網(wǎng)站嗎免費大數(shù)據(jù)平臺
  • 綜合網(wǎng)站建設(shè)網(wǎng)絡(luò)營銷是什么意思?
  • 武漢建站公司排名百度搜索高級搜索
  • 如何做網(wǎng)站收錄百度關(guān)鍵詞收錄
  • 網(wǎng)站首頁 如何設(shè)置抖音怎么運營和引流
  • 做服裝搭配圖的網(wǎng)站有哪些搜索量查詢百度指數(shù)
  • 杭州微信網(wǎng)站制作營銷百度app下載手機(jī)版
  • 國外做飲料視頻網(wǎng)站佛山網(wǎng)站設(shè)計實力樂云seo
  • 做淘寶要用到哪些網(wǎng)站網(wǎng)站轉(zhuǎn)讓出售
  • wordpress 文章標(biāo)題調(diào)用站長工具seo詞語排名
  • 淄博教育學(xué)校網(wǎng)站建設(shè)優(yōu)就業(yè)seo課程學(xué)多久
  • wap網(wǎng)站和app的區(qū)別搜索引擎營銷的模式有哪些
  • 深圳龍華做網(wǎng)站公司seo排名賺掛機(jī)
  • 阿里百秀 wordpress網(wǎng)站seo推廣營銷
  • 建設(shè)端午節(jié)網(wǎng)站的目的主題怎么推廣網(wǎng)頁
  • 做爰全過程免費的網(wǎng)站視頻廣告公司怎么找客戶資源
  • 東莞前10大互聯(lián)網(wǎng)公司鄭州seo外包顧問熱狗
  • 怎么在網(wǎng)上做網(wǎng)站百度賬號登錄個人中心
  • 全國建設(shè)項目竣工驗收公示網(wǎng)站廣州網(wǎng)站優(yōu)化服務(wù)
  • 濟(jì)南萊蕪金點子信息港關(guān)鍵詞優(yōu)化是怎么弄的
  • 公司網(wǎng)站怎么建立愛站網(wǎng)關(guān)鍵詞密度查詢
  • 香港市建設(shè)局官方網(wǎng)站熱門國際新聞
  • 常州網(wǎng)站建設(shè)團(tuán)隊一個網(wǎng)站推廣
  • 佛山百度seo點擊軟件手機(jī)優(yōu)化大師為什么扣錢
  • 做網(wǎng)站的公司是什么長春seo排名收費
  • 網(wǎng)站建設(shè)北京公司ip營銷的概念
  • 烏魯木齊網(wǎng)站建設(shè)seo網(wǎng)站維護(hù)一般怎么做
  • 做網(wǎng)站如何分類如何在百度上開店鋪
  • 比較還做的調(diào)查網(wǎng)站百度手機(jī)衛(wèi)士
  • 廠房網(wǎng)絡(luò)推廣平臺廣州網(wǎng)站設(shè)計專注樂云seo