1. 程式人生 > >詳解JVM執行原理

詳解JVM執行原理

做Java開發的幾乎都知JVM這個名詞,但是由於JVM對實際的簡單開發的來說關聯的還是不多,一般工作個一兩年(當然不包括愛學習的及專門做效能優化的什麼的),很少有人能很好的去學習及理解什麼是JVM,以及弄清楚JVM的工作原理,個人認為這塊還是非常有必要去認真瞭解及學習的,特別是剛入門或入門不久的java開發來說,JVM是Java的基石!

1.JVM簡析

作為一名Java使用者,掌握JVM的體系結構也是很有必要的。

說起Java,我們首先想到的是Java程式語言,然而事實上,Java是一種技術,它由四方面組成:Java程式語言、Java類檔案格式、Java虛擬機器和Java應用程式介面(Java API)。它們的關係如下圖所示:

Java平臺由Java虛擬機器和Java應用程式介面搭建,Java語言則是進入這個平臺的通道,用Java語言編寫並編譯的程式可以執行在這個平臺上。這個平臺的結構如下圖所示: 執行期環境代表著Java平臺,開發人員編寫Java程式碼(.java檔案),然後將之編譯成位元組碼(.class檔案),再然後位元組碼被裝入記憶體,一旦位元組碼進入虛擬機器,它就會被直譯器解釋執行,或者是被即時程式碼發生器有選擇的轉換成機器碼執行。

JVM在它的生存週期中有一個明確的任務,那就是執行Java程式,因此當Java程式啟動的時候,就產生JVM的一個例項;當程式執行結束的時候,該例項也跟著消失了。 在Java平臺的結構中, 可以看出,Java虛擬機器(JVM) 處在核心的位置,是程式與底層作業系統和硬體無關的關鍵。它的下方是移植介面,移植介面由兩部分組成:介面卡和Java作業系統, 其中依賴於平臺的部分稱為介面卡;JVM 通過移植介面在具體的平臺和作業系統上實現;在JVM 的上方是Java的基本類庫和擴充套件類庫以及它們的API, 利用Java API編寫的應用程式(application) 和小程式(Java applet) 可以在任何Java平臺上執行而無需考慮底層平臺, 就是因為有Java虛擬機器(JVM)實現了程式與作業系統的分離,從而實現了Java 的平臺無關性。

下面我們從JVM的基本概念和運過程程這兩個方面入手來對它進行深入的研究。

2.JVM基本概念

(1) 基本概念:

JVM是可執行Java程式碼的假想計算機 ,包括一套位元組碼指令集、一組暫存器、一個棧、一個垃圾回收,堆 和 一個儲存方法域。JVM是執行在作業系統之上的,它與硬體沒有直接的互動。

(2) 執行過程:

我們都知道Java原始檔,通過編譯器,能夠生產相應的.Class檔案,也就是位元組碼檔案,而位元組碼檔案又通過Java虛擬機器中的直譯器,編譯成特定機器上的機器碼 。

也就是如下:

① Java原始檔—->編譯器—->位元組碼檔案

② 位元組碼檔案—->JVM—->機器碼

每一種平臺的直譯器是不同的,但是實現的虛擬機器是相同的,這也就是Java為什麼能夠跨平臺的原因了 ,當一個程式從開始執行,這時虛擬機器就開始例項化了,多個程式啟動就會存在多個虛擬機器例項。程式退出或者關閉,則虛擬機器例項消亡,多個虛擬機器例項之間資料不能共享。

(3) 三種JVM:

① Sun公司的HotSpot;

② BEA公司的JRockit;

③ IBM公司的J9 JVM;

在JDK1.7及其以前我們所使用的都是Sun公司的HotSpot,但由於Sun公司和BEA公司都被oracle收購,jdk1.8將採用Sun公司的HotSpot和BEA公司的JRockit兩個JVM中精華形成jdk1.8的JVM。

3.JVM的體系結構

(1) Class Loader類載入器

負責載入 .class檔案,class檔案在檔案開頭有特定的檔案標示,並且ClassLoader負責class檔案的載入等,至於它是否可以執行,則由Execution Engine決定。

① 定位和匯入二進位制class檔案

② 驗證匯入類的正確性

③ 為類分配初始化記憶體

④ 幫助解析符號引用.

(2) Native Interface本地介面:

本地介面的作用是融合不同的程式語言為Java所用,它的初衷是融合C/C++程式,Java誕生的時候C/C++橫行的時候,要想立足,必須有呼叫C/C++程式,於是就在記憶體中專門開闢了一塊區域處理標記為native的程式碼,它的具體作法是Native Method Stack中登記native方法,在Execution Engine執行時載入native libraies。

目前該方法使用的越來越少了,除非是與硬體有關的應用,比如通過Java程式驅動印表機,或者Java系統管理生產裝置,在企業級應用中已經比較少見。

因為現在的異構領域間的通訊很發達,比如可以使用Socket通訊,也可以使用Web Service等。

(3) Execution Engine 執行引擎:執行包在裝載類的方法中的指令,也就是方法。

(4) Runtime data area 執行資料區:

虛擬機器記憶體或者Jvm記憶體,衝整個計算機記憶體中開闢一塊記憶體儲存Jvm需要用到的物件,變數等,執行區資料有分很多小區,分別為:方法區,虛擬機器棧,本地方法棧,堆,程式計數器。

4.JVM資料執行區詳解(棧管執行,堆管儲存):

說明:JVM調優主要就是優化 Heap堆 和 Method Area 方法區。

(1) Native Method Stack本地方法棧

它的具體做法是Native Method Stack中登記native方法,在Execution Engine執行時載入native libraies。

(2) PC Register程式計數器

每個執行緒都有一個程式計算器,就是一個指標,指向方法區中的方法位元組碼(下一個將要執行的指令程式碼),由執行引擎讀取下一條指令,是一個非常小的記憶體空間,幾乎可以忽略不記。

(3) Method Area方法區

方法區是被所有執行緒共享,所有欄位和方法位元組碼,以及一些特殊方法如建構函式,介面程式碼也在此定義。簡單說,所有定義的方法的資訊都儲存在該區域,此區域屬於共享區間。

靜態變數+常量+類資訊+執行時常量池存在方法區中,例項變數存在堆記憶體中。

(4) Stack 棧

① 棧是什麼

棧也叫棧記憶體,主管Java程式的執行,是線上程建立時建立,它的生命期是跟隨執行緒的生命期,執行緒結束棧記憶體也就釋放,對於棧來說不存在垃圾回收問題,只要執行緒一結束該棧就Over,生命週期和執行緒一致,是執行緒私有的。

基本型別的變數和物件的引用變數都是在函式的棧記憶體中分配。

② 棧儲存什麼?

棧幀中主要儲存3類資料:

本地變數(Local Variables):輸入引數和輸出引數以及方法內的變數;

棧操作(Operand Stack):記錄出棧、入棧的操作;

棧幀資料(Frame Data):包括類檔案、方法等等。

③ 棧執行原理

棧中的資料都是以棧幀(Stack Frame)的格式存在,棧幀是一個記憶體區塊,是一個數據集,是一個有關方法和執行期資料的資料集,當一個方法A被呼叫時就產生了一個棧幀F1,並被壓入到棧中,A方法又呼叫了B方法,於是產生棧幀F2也被壓入棧,B方法又呼叫了C方法,於是產生棧幀F3也被壓入棧…… 依次執行完畢後,先彈出後進......F3棧幀,再彈出F2棧幀,再彈出F1棧幀。

遵循“先進後出”/“後進先出”原則。

(5) Heap 堆

堆這塊區域是JVM中最大的,應用的物件和資料都是存在這個區域,這塊區域也是執行緒共享的,也是 gc 主要的回收區,一個 JVM 例項只存在一個堆類存,堆記憶體的大小是可以調節的。類載入器讀取了類檔案後,需要把類、方法、常變數放到堆記憶體中,以方便執行器執行,堆記憶體分為三部分:

① 新生區

新生區是類的誕生、成長、消亡的區域,一個類在這裡產生,應用,最後被垃圾回收器收集,結束生命。新生區又分為兩部分:伊甸區(Eden space)和倖存者區(Survivor pace),所有的類都是在伊甸區被new出來的。倖存區有兩個:0區(Survivor 0 space)和1區(Survivor 1 space)。當伊甸園的空間用完時,程式又需要建立物件,JVM的垃圾回收器將對伊甸園進行垃圾回收(Minor GC),將伊甸園中的剩餘物件移動到倖存0區。若倖存0區也滿了,再對該區進行垃圾回收,然後移動到1區。那如果1去也滿了呢?再移動到養老區。若養老區也滿了,那麼這個時候將產生Major GC(FullGCC),進行養老區的記憶體清理。若養老區執行Full GC 之後發現依然無法進行物件的儲存,就會產生OOM異常“OutOfMemoryError”。

如果出現java.lang.OutOfMemoryError: Java heap space異常,說明Java虛擬機器的堆記憶體不夠。原因有二:

a.Java虛擬機器的堆記憶體設定不夠,可以通過引數-Xms、-Xmx來調整。

b.程式碼中建立了大量大物件,並且長時間不能被垃圾收集器收集(存在被引用)。

② 養老區

養老區用於儲存從新生區篩選出來的 JAVA 物件,一般池物件都在這個區域活躍。

③ 永久區

永久儲存區是一個常駐記憶體區域,用於存放JDK自身所攜帶的 Class,Interface 的元資料,也就是說它儲存的是執行環境必須的類資訊,被裝載進此區域的資料是不會被垃圾回收器回收掉的,關閉 JVM 才會釋放此區域所佔用的記憶體。

如果出現java.lang.OutOfMemoryError: PermGen space,說明是Java虛擬機器對永久代Perm記憶體設定不夠。原因有二:

a. 程式啟動需要載入大量的第三方jar包。例如:在一個Tomcat下部署了太多的應用。

b. 大量動態反射生成的類不斷被載入,最終導致Perm區被佔滿。

說明:

Jdk1.6及之前:常量池分配在永久代 。

Jdk1.7:有,但已經逐步“去永久代” 。

Jdk1.8及之後:無(java.lang.OutOfMemoryError: PermGen space,這種錯誤將不會出現在JDK1.8中)。

說明:方法區和堆記憶體的異議:

實際而言,方法區和堆一樣,是各個執行緒共享的記憶體區域,它用於儲存虛擬機器載入的:類資訊+普通常量+靜態常量+編譯器編譯後的程式碼等等,雖然JVM規範將方法區描述為堆的一個邏輯部分,但它卻還有一個別名叫做Non-Heap(非堆),目的就是要和堆分開。

對於HotSpot虛擬機器,很多開發者習慣將方法區稱之為“永久代(Parmanent Gen)”,但嚴格本質上說兩者不同,或者說使用永久代來實現方法區而已,永久代是方法區的一個實現,jdk1.7的版本中,已經將原本放在永久代的字串常量池移走。

常量池(Constant Pool)是方法區的一部分,Class檔案除了有類的版本、欄位、方法、介面等描述資訊外,還有一項資訊就是常量池,這部分內容將在類載入後進入方法區的執行時常量池中存放。

5.堆記憶體調優簡介

程式碼測試:

public class JVMTest {

public static void main(String[] args){

long maxMemory = Runtime.getRuntime().maxMemory();//返回Java虛擬機器試圖使用的最大記憶體量。

Long totalMemory = Runtime. getRuntime().totalMemory();//返回Java虛擬機器中的記憶體總量。

System.out.println("MAX_MEMORY ="+maxMemory +"(位元組)、"+(maxMemory/(double)1024/1024) + "MB");

System.out.println("TOTAL_ MEMORY = "+totalMemory +"(位元組)"+(totalMemory/(double)1024/1024) + "MB");

}

}

說明:在Run as ->Run Configurations中輸入"-XX:+PrintGCDetails"可以檢視堆記憶體執行原理圖:

(1) 在jdk1.7中:

(2) 在jdk1.8中:

6.通過引數設定自動觸發垃圾回收:

public class JVMTest {

public static void main(String[] args){

long maxMemory = Runtime.getRuntime().maxMemory();//返回Java虛擬機器試圖使用的最大記憶體量。

Long totalMemory = Runtime. getRuntime().totalMemory();//返回Java虛擬機器中的記憶體總量。

System.out.println("MAX_MEMORY ="+maxMemory +"(位元組)、"+(maxMemory/(double)1024/1024) + "MB");

System.out.println("TOTAL_ MEMORY = "+totalMemory +"(位元組)"+(totalMemory/(double)1024/1024) + "MB");

String str = "www.baidu.com";

while(true){

str += str + new Random().nextInt(88888888) + new Random().nextInt(99999999);

}

}

}

在Run as ->Run Configurations中輸入設定“-Xmx8m –Xms8m –xx:+PrintGCDetails”可以參看垃圾回收機制原理:

相關推薦

JVM執行原理

做Java開發的幾乎都知JVM這個名詞,但是由於JVM對實際的簡單開發的來說關聯的還是不多,一般工作個一兩年(當然不包括愛學習的及專門做效能優化的什麼的),很少有人能很好的去學習及理解什麼是JVM,以及弄清楚JVM的工作原理,個人認為這塊還是非常有必要去認真瞭解及學習的,特別

(轉)Java JVM 工作原理和流程

移植 獲得 代碼 適配 調用 tac 階段 main方法 等待 作為一名Java使用者,掌握JVM的體系結構也是必須的。說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Ja

Java JVM 工作原理和流程

str literal 狀態 應用 流程 href ctu 局部變量 自定義 作為一名Java使用者,掌握JVM的體系結構也是必須的。說起Java,人們首先想到的是Java編程語言,然而事實上,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Jav

Hadoop偽分佈安裝+MapReduce執行原理+基於MapReduce的KNN演算法實現

本篇部落格將圍繞Hadoop偽分佈安裝+MapReduce執行原理+基於MapReduce的KNN演算法實現這三個方面進行敘述。 (一)Hadoop偽分佈安裝 1、簡述Hadoop的安裝模式中–偽分佈模式與叢集模式的區別與聯絡. Hadoop的安裝方式有三種:本地模式,偽分佈模式

JVM原理相關 (轉)Java JVM 工作原理和流程

(轉)Java 詳解 JVM 工作原理和流程   作為一名Java使用者,掌握JVM的體系結構也是必須的。說起Java,人們首先想到的是Java程式語言,然而事實上,Java是一種技術,它由四方面組成:Java程式語言、Java類檔案格式、Java虛擬機器和Java應用程式介

webpack核心概念及其執行原理

* Entry: 入口, webpack執行構建的第一步將從Entry開始,可抽象成輸入 * Module: 模組,在webpcak中一切皆模組,一個模組對應一個檔案。webpack會從配置的Entry開始遞迴找出所有依賴的模組。 * Chunk: 程式碼塊,一個Chunk由多個模組組合

JavaJVM工作原理和流程

作為一名Java使用者,掌握JVM的體系結構也是必須的。 說起Java,人們首先想到的是Java程式語言,然而事實上,Java是一種技術,它由四方面組成:Java程式語言、Java類檔案格式、Java虛擬機器和Java應用程式介面(Java API)。它們的關係如下圖所示:

JVM執行原理

       新生區是類的誕生、成長、消亡的區域,一個類在這裡產生,應用,最後被垃圾回收器收集,結束生命。新生區又分為兩部分:伊甸區(Eden space)和倖存者區(Survivor pace),所有的類都是在伊甸區被new出來的。倖存區有兩個:0區(Survivor 0 space)和1區(Survivo

JVM中堆、棧、方法區(對象、值)是如何調用執行

沒有 自定義 成了 coo 裏的 原始類型 元素 動手 完成 這兩天看了一下深入淺出JVM這本書,推薦給高級的java程序員去看,對你了解JAVA的底層和運行機制有比較大的幫助。 先了解具體的概念:JAVA的JVM的內存可分為3個區:堆(heap)、棧(stack)和方法區

JVM之:執行時常量池

[toc] # 簡介 JVM在執行的時候會對class檔案進行載入,連結和初始化的過程。class檔案中定義的常量池在JVM載入之後會發生什麼神奇的變化呢?快來看一看吧。 # class檔案中的常量池 之前我們在講class檔案的結構時,提到了每個class檔案都有一個常量池,常量池中存了些什麼東西呢

Java虛擬機——JVM常見問題總結

can 語言 嘗試 意思 是把 fff rom com serial 【正文】 聲明:本文只是做一個總結,有關jvm的詳細知識可以參考之前的系列文章,尤其是那篇:Java虛擬機詳解04—-GC算法和種類。那篇文章和本文是面試時的重點。 面試必問關鍵詞:JVM垃圾回收、類加載

JVM內存管理與垃圾回收機制 (上)

JVM 內存結構Java應用程序是運行在JVM上的,得益於JVM的內存管理和垃圾收集機制,開發人員的效率得到了顯著提升,也不容易出現內存溢出和泄漏問題。但正是因為開發人員把內存的控制權交給了JVM,一旦出現內存方面的問題,如果不了解JVM的工作原理,將很難排查錯誤。本文將從理論角度介紹虛擬機的內存管理和垃圾回

純幹貨iptables工作原理以及使用方法

rip -a sports 公網 寫法 內網ip 行處理 外部 是否 簡介 網絡中的防火墻,是一種將內部和外部網絡分開的方法,是一種隔離技術。防火墻在內網與外網通信時進行訪問控制,依據所設置的規則對數據包作出判斷,最大限度地阻止網絡中不法分子破壞企業網絡,從而加強了企業網絡

JVM執行原理

裝載 font 消失 log enter 適配器 好用 依賴 任務 ,Java是一種技術,它由四方面組成:Java編程語言、Java類文件格式、Java虛擬機和Java應用程序接口(Java API)。它們的關系如下圖所示: 運行期環境代表著Java平臺,開發人員編寫Ja

Python程序、執行緒、協程執行效能、效率(tqdm)

多程序實踐——multiprocessing 筆者最近在實踐多程序發現multiprocessing,真心很好用,不僅加速了運算,同時可以GPU呼叫,而且互相之間無關聯,這樣可以很放心的進行計算。 譬如(參考:多程序): from multiprocessing import Pool

HTTP 1 -工作原理

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

BadVPN之--組網原理剖析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

JavaScript 預編譯原理(和其他語言很不一樣)

JavaScript 預編譯原理 今天用了大量時間複習了作用域、預編譯等等知識 看了很多博文,翻開了以前看過的書(好像好多書都不會講預編譯) 發現當初覺得自己學的很明白,其實還是存在一些思維誤區 (很多博文具有誤導性) 今晚就整理了一下凌亂的思路 先整理一下預編譯的知識吧,日後有時間再把作用

Linux : select() 和 實現原理【轉】

https://www.cnblogs.com/sky-heaven/p/7205491.html#4119169   轉自:http://blog.csdn.net/huntinux/article/details/39289317 原文:http://blog.csdn.n

JVM記憶體管理與垃圾回收機制1 - 記憶體管理

Java應用程式是執行在JVM上的,得益於JVM的記憶體管理和垃圾收集機制,開發人員的效率得到了顯著提升,也不容易出現記憶體溢位和洩漏問題。但正是因為開發人員把記憶體的控制權交給了JVM,一旦出現記憶體方面的問題,如果不瞭解JVM的工作原理,將很難排查錯誤。本文將從理論角度介紹虛擬機器的記憶