寫在前面
最近,一直有小伙伴讓我整理下關于JVM的知識,經過十幾天的收集與整理,初版算是整理出來了,希望對大家有所幫助,
記得點贊收藏加關注哦 ,需要下載PDF版本和更多知識點、面試題的朋友可以點一點下方鏈接免費領取
鏈接:點這里!!! 799215493 暗號:CSDN

JDK 是什么?
JDK 是用于支持 Java 程式開發的最小環境,
- Java 程式設計語言
- Java 虛擬機
- Java API類別庫
JRE 是什么?
JRE 是支持 Java 程式運行的標準環境,
- Java SE API 子集
- Java 虛擬機
Java歷史版本的特性?
Java Version SE 5.0
- 引入泛型;
- 增強回圈,可以使用迭代方式;
- 自動裝箱與自動拆箱;
- 型別安全的列舉;
- 可變引數;
- 靜態引入;
- 元資料(注解);
- 引入Instrumentation,
Java Version SE 6
- 支持腳本語言;
- 引入JDBC 4.0 API;
- 引入Java Compiler API;
- 可插拔注解;
- 增加對Native PKI(Public Key Infrastructure)、Java GSS(Generic Security Service)、Kerberos和LDAP(Lightweight Directory Access Protocol)的支持;
- 繼承Web Services;
- 做了很多優化,
Java Version SE 7
- switch陳述句塊中允許以字串作為分支條件;
- 在創建泛型物件時應用型別推斷;
- 在一個陳述句塊中捕獲多種例外;
- 支持動態語言;
- 支持try-with-resources;
- 引入Java NIO.2開發包;
- 數值型別可以用2進制字串表示,并且可以在字串表示中添加下劃線;
- 鉆石型語法;
- null值的自動處理,
Java 8
- 函式式介面
- Lambda運算式
- Stream API
- 介面的增強
- 時間日期增強API
- 重復注解與型別注解
- 默認方法與靜態方法
- Optional 容器類
運行時資料區域包括哪些?
- 程式計數器
- Java 虛擬機堆疊
- 本地方法堆疊
- Java 堆
- 方法區
- 運行時常量池
- 直接記憶體
程式計數器(執行緒私有)
程式計數器(Program Counter Register)是一塊較小的記憶體空間,可以看作是當前執行緒所執行位元組碼的行號指示器,分支、回圈、跳轉、例外處理、執行緒恢復等基礎功能都需要依賴這個計數器完成,
由于 Java 虛擬機的多執行緒是通過執行緒輪流切換并分配處理器執行時間的方式實作的,為了執行緒切換后能恢復到正確的執行位置,每條執行緒都需要一個獨立的程式計數器,各執行緒之間的計數器互不影響,獨立存盤,
- 如果執行緒正在執行的是一個 Java 方法,計數器記錄的是正在執行的虛擬機位元組碼指令的地址;
- 如果正在執行的是 Native 方法,這個計數器的值為空,
程式計數器是唯一一個沒有規定任何 OutOfMemoryError 的區域,
Java 虛擬機堆疊(執行緒私有)
Java 虛擬機堆疊(Java Virtual Machine Stacks)是執行緒私有的,生命周期與執行緒相同,
虛擬機堆疊描述的是 Java 方法執行的記憶體模型:每個方法被執行的時候都會創建一個堆疊幀(Stack Frame),存盤
- 區域變數表
- 操作堆疊
- 動態鏈接
- 方法出口
每一個方法被呼叫到執行完成的程序,就對應著一個堆疊幀在虛擬機堆疊中從入堆疊到出堆疊的程序,
這個區域有兩種例外情況:
- StackOverflowError:執行緒請求的堆疊深度大于虛擬機所允許的深度
- OutOfMemoryError:虛擬機堆疊擴展到無法申請足夠的記憶體時
本地方法堆疊(執行緒私有)
虛擬機堆疊為虛擬機執行 Java 方法(位元組碼)服務,
本地方法堆疊(Native Method Stacks)為虛擬機使用到的 Native 方法服務,
Java 堆(執行緒共享)
Java 堆(Java Heap)是 Java 虛擬機中記憶體最大的一塊,Java 堆在虛擬機啟動時創建,被所有執行緒共享,
作用:存放物件實體,垃圾收集器主要管理的就是 Java 堆,Java 堆在物理上可以不連續,只要邏輯上連續即可,
方法區(執行緒共享)
方法區(Method Area)被所有執行緒共享,用于存盤已被虛擬機加載的類資訊、常量、靜態變數、即時編譯器編譯后的代碼等資料,
和 Java 堆一樣,不需要連續的記憶體,可以選擇固定的大小,更可以選擇不實作垃圾收集,
運行時常量池
運行時常量池(Runtime Constant Pool)是方法區的一部分,保存 Class 檔案中的符號參考、翻譯出來的直接參考,運行時常量池可以在運行期間將新的常量放入池中,
如何判斷物件是否“死去”?
- 參考計數法
- 根搜索演算法
什么是參考計數法?
給物件添加一個參考計數器,每當有一個地方參考它,計數器就+1,;當參考失效時,計數器就-1;任何時刻計數器都為0的物件就是不能再被使用的,
參考計數法的缺點?
很難解決物件之間的回圈參考問題,
Java 的4種參考方式?
在 JDK 1.2 之后,Java 對參考的概念進行了擴充,將參考分為
- 強參考 Strong Reference
- 軟參考 Soft Reference
- 弱參考 Weak Reference
- 虛參考 Phantom Reference
強參考
Object obj = new Object();
代碼中普遍存在的,像上述的參考,只要強參考還在,垃圾收集器永遠不會回收掉被參考的物件,
軟參考
用來描述一些還有用,但并非必須的物件,軟參考所關聯的物件,有在系統將要發生記憶體溢位例外之前,將會把這些物件列進回收范圍,并進行第二次回收,如果這次回識訓是沒有足夠的記憶體,才會拋出記憶體例外,提供了 SoftReference 類實作軟參考,
弱參考
描述非必須的物件,強度比軟參考更弱一些,被弱參考關聯的物件,只能生存到下一次垃圾收集發生前,當垃圾收集器作業時,無論當前記憶體是否足夠,都會回收掉只被弱參考關聯的物件,提供了 WeakReference 類來實作弱參考,
虛參考
一個物件是否有虛參考,完全不會對其生存時間夠成影響,也無法通過虛參考來取得一個物件實體,為一個物件關聯虛參考的唯一目的,就是希望在這個物件被收集器回收時,收到一個系統通知,提供了 PhantomReference 類來實作虛參考,
有哪些垃圾收集演算法?
- 標記-清除演算法
- 復制演算法
- 標記-整理演算法
- 分代收集演算法
分代收集演算法
根據物件的存活周期,將記憶體劃分為幾塊,一般是把 Java 堆分為新生代和老年代,這樣就可以根據各個年代的特點,采用最適當的收集演算法,
- 新生代:每次垃圾收集時會有大批物件死去,只有少量存活,所以選擇復制演算法,只需要少量存活物件的復制成本就可以完成收集,
- 老年代:物件存活率高、沒有額外空間對它進行分配擔保,必須使用“標記-清理”或“標記-整理”演算法進行回收,
記得點贊收藏加關注哦 ,需要下載PDF版本和更多知識點、面試題的朋友可以點一點下方鏈接免費領取
鏈接:點這里!!! 799215493 暗號:CSDN
Minor GC 和 Full GC有什么區別?
Minor GC:新生代 GC,指發生在新生代的垃圾收集動作,因為 Java 物件大多死亡頻繁,所以 Minor GC 非常頻繁,一般回收速度較快,
Full GC:老年代 GC,也叫 Major GC,速度一般比 Minor GC 慢 10 倍以上,
Java 記憶體
為什么要將堆記憶體磁區?
對于一個大型的系統,當創建的物件及方法變數比較多時,即堆記憶體中的物件比較多,如果逐一分析物件是否該回收,效率很低,磁區是為了進行模塊化管理,管理不同的物件及變數,以提高 JVM 的執行效率,
堆記憶體分為哪幾塊?
- Young Generation Space 新生區(也稱新生代)
- Tenure Generation Space養老區(也稱舊生代)
- Permanent Space 永久存盤區
分代收集演算法
記憶體分配有哪些原則?
- 物件優先分配在 Eden
- 大物件直接進入老年代
- 長期存活的物件將進入老年代
- 動態物件年齡判定
- 空間分配擔保
Young Generation Space (采用復制演算法)
主要用來存盤新創建的物件,記憶體較小,垃圾回收頻繁,這個區又分為三個區域:一個 Eden Space 和兩個 Survivor Space,
- 當物件在堆創建時,將進入年輕代的Eden Space,
- 垃圾回收器進行垃圾回收時,掃描Eden Space和A Suvivor Space,如果物件仍然存活,則復制到B Suvivor Space,如果B Suvivor Space已經滿,則復制 Old Gen
- 掃描A Suvivor Space時,如果物件已經經過了幾次的掃描仍然存活,JVM認為其為一個Old物件,則將其移到Old Gen,
- 掃描完畢后,JVM將Eden Space和A Suvivor Space清空,然后交換A和B的角色(即下次垃圾回收時會掃描Eden Space和B Suvivor Space,
Tenure Generation Space(采用標記-整理演算法)
主要用來存盤長時間被參考的物件,它里面存放的是經過幾次在 Young Generation Space 進行掃描判斷過仍存活的物件,記憶體較大,垃圾回收頻率較小,
Permanent Space
存盤不變的類定義、位元組碼和常量等,
類加載器
類加載器的作用是什么?
類加載器實作類的加載動作,同時用于確定一個類,對于任意一個類,都需要由加載它的類加載器和這個類本身一同確立其在Java虛擬機中的唯一性,即使兩個類來源于同一個Class檔案,只要加載它們的類加載器不同,這兩個類就不相等,
類加載器有哪些?
- 啟動類加載器(Bootstrap ClassLoader):使用C++實作(僅限于HotSpot),是虛擬機自身的一部分,負責將存放在\lib目錄中的類別庫加載到虛擬機中,其無法被Java程式直接參考,
- 擴展類加載器(Extention ClassLoader)由ExtClassLoader實作,負責加載\lib\ext目錄中的所有類別庫,開發者可以直接使用,
- 應用程式類加載器(Application ClassLoader):由APPClassLoader實作,負責加載用戶類路徑(ClassPath)上所指定的類別庫,
類加載機制
什么是雙親委派模型?
雙親委派模型(Parents Delegation Model)要求除了頂層的啟動類加載器外,其余加載器都應當有自己的父類加載器,類加載器之間的父子關系,通過組合關系復用,
作業程序:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器完成,每個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到頂層的啟動類加載器中,只有到父加載器反饋自己無法完成這個加載請求(它的搜索范圍沒有找到所需的類)時,子加載器才會嘗試自己去加載,
為什么要使用雙親委派模型,組織類加載器之間的關系?
Java類隨著它的類加載器一起具備了一種帶優先級的層次關系,比如java.lang.Object,它存放在rt.jar中,無論哪個類加載器要加載這個類,最終都是委派給啟動類加載器進行加載,因此Object類在程式的各個類加載器環境中,都是同一個類,
如果沒有使用雙親委派模型,讓各個類加載器自己去加載,那么Java型別體系中最基礎的行為也得不到保障,應用程式會變得一片混亂,
什么是類加載機制?
Class檔案描述的各種資訊,都需要加載到虛擬機后才能運行,虛擬機把描述類的資料從Class檔案加載到記憶體,并對資料進行校驗、轉換決議和初始化,最終形成可以被虛擬機直接使用的Java型別,這就是虛擬機的類加載機制,
虛擬機和物理機的區別是什么?
這兩種機器都有代碼執行的能力,但是:
- 物理機的執行引擎是直接建立在處理器、硬體、指令集和作業系統層面的,
- 虛擬機的執行引擎是自己實作的,因此可以自行制定指令集和執行引擎的結構體系,并且能夠執行那些不被硬體直接支持的指令集格式,
Java 方法呼叫
什么是方法呼叫?
方法呼叫唯一的任務是確定被呼叫方法的版本(呼叫哪個方法),暫時還不涉及方法內部的具體運行程序,
Java的方法呼叫,有什么特殊之處?
Class檔案的編譯程序不包含傳統編譯的連接步驟,一切方法呼叫在Class檔案里面存盤的都只是符號參考,而不是方法在實際運行時記憶體布局中的入口地址,這使得Java有強大的動態擴展能力,但使Java方法的呼叫程序變得相對復雜,需要在類加載期間甚至到運行時才能確定目標方法的直接參考,
Java虛擬機呼叫位元組碼指令有哪些?
- invokestatic:呼叫靜態方法
- invokespecial:呼叫實體構造器方法、私有方法和父類方法
- invokevirtual:呼叫所有的虛方法
- invokeinterface:呼叫介面方法
虛擬機是如何執行方法里面的位元組碼指令的?
解釋執行(通過解釋器執行)
編譯執行(通過即時編譯器產生本地代碼)
解釋執行
當主流的虛擬機中都包含了即時編譯器后,Class檔案中的代碼到底會被解釋執行還是編譯執行,只有虛擬機自己才能準確判斷,
Javac編譯器完成了程式代碼經過詞法分析、語法分析到抽象語法樹,再遍歷語法樹生成線性的位元組碼指令流的程序,因為這一動作是在Java虛擬機之外進行的,而解釋器在虛擬機的內部,所以Java程式的編譯是半獨立的實作,
最后
由于篇幅有限,這里只展示一部分,需要完整版的朋友可以點一點下方鏈接免費領取~
在這里也為大家整理了各個知識點模塊整理檔案(微服務、資料庫、mysql、jvm、Redis等都有)和更多大廠面試真題,有需要的朋友可以點一點下方鏈接免費領取
鏈接:點這里!!! 799215493 暗號:CSDN


轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/226840.html
標籤:java
