JVM總體架構


什么是JVM?

JVM(Java Virtual Machine,Java虛擬機)

用記事本寫第一個java程序HelloWorld

第一步:寫java源代碼程序:HelloWorld.java

第二步:編譯java源代碼程序,生成HelloWorld.class文件,字節碼文件

第三步:運行程序.(在JVM里運行的)

JVM是JRE的一部分。它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的。JVM有自己完善的硬件架構,如處理器、堆棧、寄存器等,還具有相應的指令系統。Java語言最重要的特點就是跨平台運行。使用JVM就是為了支持與操作系統無關,實現跨平台。所以,JAVA虛擬機JVM是屬於JRE的,而現在我們安裝JDK時也附帶安裝了JRE,JRE又包含了JVM.

對於Java程序員來說,JAVA虛擬機底層的指令,不是我們核心關注的內容,我們關注的是我們寫的java程序在jvm中運行時需要的內存,內存是由JVM自動管理的,由於程序或硬件的原因可能會出現內存泄漏或溢出的問題導致運行的程序崩潰,不了解JVM的內存結構和各個內存區域的工作職責,將對解決這類問題帶來很大的麻煩,所以學習java到一定程度的時候,是必須要學習jvm里的知識點的,我們先粗略地了解一下整個JVM的構架,來開始我們的學習:

JVM被分為三個主要的子系統

(1)類加載器子系統---執行.class編譯后的文件,載入到jvm的體系中,然后進行初始化的操作,把相關的數據放到內存中的某些區域,做具體的內存分配的操作

(2)運行時數據區(我們核心關注這里的棧、堆、方法區)【這里面所存放的是類加載加載后的一些數據】

(3)執行引擎---是從內存中(可以任務是運行時數據區)獲取相關數據來執行,執行后在把數據返還到內存中

         1.解釋器 :運行字節碼文件

         2. 編譯器:把字節碼文件(.class文件)編譯成根據當前操作系統能夠執行的文件,他決定跨平台

         3. 垃圾回收器:會把內存中產生的垃圾數據進行回收清理,進行釋放內存,清空時會根據jvm中垃圾回收算法進行回收,且自動進行回收,我們主要調優就是調這里,通過合適的算法進行對jvm的優化處理,避免出現卡頓,內存溢出等情況,盡可能的高效運行

         4.JIN:(java本地接口)—怎么調用C語言的這些代碼

         5.本地方法庫:本地方法棧為虛擬機使用到的 native 方法服務

虛擬機棧

虛擬機棧(Java Virtual Machine Stacks)和線程是緊密聯系的,每創建一個線程時就會對應創建一個Java棧,所以Java棧也是"線程私有"的內存區域(每個棧與每個棧互不影響),這個棧中又會對應包含多個棧幀(棧幀就是方法),每調用一個方法時就會往棧中創建並壓入一個棧幀(創建棧幀),棧幀是用來存儲方法數據和部分過程結果的數據結構,每一個方法從調用到最終返回結果的過程,就對應一個棧幀從入棧到出棧的過程。

虛擬機棧是一個后入先出的數據結構,線程運行過程中,只有一個棧幀是處於活躍狀態的,被稱為"當前活動幀棧",當前活動幀棧始終是虛擬機棧的棧頂元素。

方法區

方法區(Method Area)是用於存儲類結構信息的地方,包括常量池、靜態變量(不易過多的創建靜態的變量,因為類加載器只要一加載就會把靜態變量加載到方法區中,導致運行效率降低,減小其他內存區域)、構造函數等類型信息,類型信息是由類加載器在類加載時從類文件中提取出來的。

方法區同樣存在垃圾收集,因為用戶通過自定義加載器加載的一些類同樣會成為垃圾,JVM會回收一個未被引用類所占的空間,以使方法區的空間達到最小, 但是方法區的垃圾不易被回收。

方法區中還存在着常量池,常量池包含着一些常量和符號引用(加載類的連接階段中的解析過程會將符號引用轉換為直接引用)。

方法區是線程共享的。

堆(heap)是存儲java實例或者對象的地方,是GC的主要區域,同樣是線程共享的內存區域。也重點學習的地方。

案例分析一:

 


 2019-10-09新增開始

2019-10-09新增結束


案例分析二


 2019-10-09新增開始

2019-10-09新增結束


上面main方法中運行的程序過程如下:

(1)用戶創建了一個Student對象,運行時JVM首先會去方法區尋找該對象的類型信息,沒有則使用類加載器classloader將Student.class字節碼文件加載至內存中的方法區,並將Student   類的類型信息存放至方法區。

(2)接着JVM在堆中為新的Student實例分配內存空間,這個實例持有着指向方法區的Student類型信息的引用,引用指的是類型信息在方法區中的內存地址。

(3)在此運行的JVM進程中,會首先起一個線程跑該用戶程序,而創建線程的同時也創建了一個虛擬機棧,虛擬機棧用來跟蹤線程運行中的一系列方法調用的過程,每調用一個方法就會創建並往棧中壓入一個棧幀,棧幀用來存儲方法的參數,局部變量和運算過程的臨時數據。上面程序中的stu是對Student的引用,就存放於棧中,並持有指向堆中Student實例的內存地址。

(4)JVM根據stu引用持有的堆中對象的內存地址,定位到堆中的Student實例,由於堆中實例持有指向方法區的Student類型信息的引用,從而獲得add()方法的字節碼信息,接着執行add()方法包含的指令。

總結

  1. 所有線程共享的內存數據區:方法區,堆。而虛擬機棧,本地方法棧和程序計數器都是線程私有的。
  2. 存放於棧中的東西如下:
    • 每個線程包含一個棧區,棧中只保存基礎數據類型的對象和自定義對象的引用(不是對象)。對象都存放在堆區中。
    • 每個棧中的數據(基礎數據類型和對象引用)都是私有的,其他棧不能訪問。
    • 方法的形式參數,方法調用完后從棧空間回收
    • 引用對象的地址,引用完后,棧空間地址立即被回收,堆空間等待GC
  3. 存放於堆中的東西如下:
    • 存儲的全部是對象,每個對象包含一個與之對應的class信息
    • Jvm只有一個堆區(heap)被所有線程共享,堆區中不存放基本類型和對象引用,只存放對象本身
  4. 存放於方法區中的東西如下:
    • 存放線程所執行的字節碼指令
    • 跟堆一樣.被所有線程共享.方法區包含:所有的class和static變量
    • 常量池位於方法區中,見如下圖示說明

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM