1. 程式人生 > >2萬字長文包教包會 JVM 記憶體結構 保姆級學習筆記

2萬字長文包教包會 JVM 記憶體結構 保姆級學習筆記

> 寫這篇的主要原因呢,就是為了能在簡歷上寫個“熟悉JVM底層結構”,另一個原因就是能讓讀我文章的大家也寫上這句話,真是個助人為樂的帥小夥。。。。嗯,不單單只是面向面試學習哈,更重要的是構建自己的 JVM 知識體系,Javaer 們技術棧要有廣度,但是 JVM 的掌握必須有深度 > > 點贊+收藏 就學會系列,文章收錄在 GitHub [JavaKeeper](https://github.com/Jstarfish/JavaKeeper) ,N線網際網路開發必備技能兵器譜,筆記自取 ## 直擊面試 反正我是帶著這些問題往下讀的 - 說一下 JVM 執行時資料區吧,都有哪些區?分別是幹什麼的? - Java 8 的記憶體分代改進 - 舉例棧溢位的情況? - 調整棧大小,就能儲存不出現溢位嗎? - 分配的棧記憶體越大越好嗎? - 垃圾回收是否會涉及到虛擬機器棧? - 方法中定義的區域性變數是否執行緒安全? ------ ![](https://tva1.sinaimg.cn/large/007S8ZIlly1gg9kuge8ovj32150tt7cd.jpg) # 執行時資料區 記憶體是非常重要的系統資源,是硬碟和 CPU 的中間倉庫及橋樑,承載著作業系統和應用程式的實時執行。JVM 記憶體佈局規定了 Java 在執行過程中記憶體申請、分配、管理的策略,保證了 JVM 的高效穩定執行。不同的 JVM 對於記憶體的劃分方式和管理機制存在著部分差異。 下圖是 JVM 整體架構,中間部分就是 Java 虛擬機器定義的各種執行時資料區域。 ![jvm-framework](https://tva1.sinaimg.cn/large/0082zybply1gc6fz21n8kj30u00wpn5v.jpg) Java 虛擬機器定義了若干種程式執行期間會使用到的執行時資料區,其中有一些會隨著虛擬機器啟動而建立,隨著虛擬機器退出而銷燬。另外一些則是與執行緒一一對應的,這些與執行緒一一對應的資料區域會隨著執行緒開始和結束而建立和銷燬。 - 執行緒私有:程式計數器、棧、本地棧 - 執行緒共享:堆、堆外記憶體(永久代或元空間、程式碼快取) > 下面我們就來一一解毒下這些記憶體區域,先從最簡單的入手 ## 一、程式計數器 程式計數暫存器(**Program Counter Register**),Register 的命名源於 CPU 的暫存器,暫存器儲存指令相關的執行緒資訊,CPU 只有把資料裝載到暫存器才能夠執行。 這裡,並非是廣義上所指的物理暫存器,叫程式計數器(或PC計數器或指令計數器)會更加貼切,並且也不容易引起一些不必要的誤會。**JVM 中的 PC 暫存器是對物理 PC 暫存器的一種抽象模擬**。 程式計數器是一塊較小的記憶體空間,可以看作是當前執行緒所執行的位元組碼的**行號指示器**。 ### 1.1 作用 PC 暫存器用來儲存指向下一條指令的地址,即將要執行的指令程式碼。由執行引擎讀取下一條指令。 ![jvm-pc-counter](https://tva1.sinaimg.cn/large/0082zybply1gc5kmznm1sj31m50u0wph.jpg) (分析:進入class檔案所在目錄,執行 `javap -v xx.class` 反解析(或者通過 IDEA 外掛 `Jclasslib` 直接檢視,上圖),可以看到當前類對應的Code區(彙編指令)、本地變量表、異常表和程式碼行偏移量對映表、常量池等資訊。) ### 1.2 概述 - 它是一塊很小的記憶體空間,幾乎可以忽略不計。也是執行速度最快的儲存區域 - 在 JVM 規範中,每個執行緒都有它自己的程式計數器,是執行緒私有的,生命週期與執行緒的生命週期一致 - 任何時間一個執行緒都只有一個方法在執行,也就是所謂的**當前方法**。如果當前執行緒正在執行的是 Java 方法,程式計數器記錄的是 JVM 位元組碼指令地址,如果是執行 natice 方法,則是未指定值(undefined) - 它是程式控制流的指示器,分支、迴圈、跳轉、異常處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成 - 位元組碼直譯器工作時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令 - 它是唯一一個在 JVM 規範中沒有規定任何 `OutOfMemoryError` 情況的區域 >