
我們都知道,我們寫的Java程式需要先經過編譯,生成了.class檔案(位元組碼檔案),然而,計算機并不能直接解釋.class檔案里面的內容,這時候就需要一個能加載、解釋.class檔案并且能按.class檔案里的內容進行處理的一個東西--JVM,
JVM,就是Java虛擬機,它是一種規范,有針對不同系統的特定實作(Linux,Windows,macOS),這樣,相同的位元組碼就能在不同的系統上運行,實作了跨平臺運行(Write Once, Run Anywhere),
JVM的記憶體結構

上圖是JDK1.8的JVM記憶體結構,可以看出記憶體結構分為程式計數器、Java虛擬機堆疊、本地方法堆疊、堆、元空間,其中程式計數器、Java虛擬機堆疊、本地方法堆疊是執行緒獨享的(按執行緒隔離),其生命周期和所在執行緒相同,而堆、元空間是執行緒共享的,
程式計數器
程式計數器是一塊較小的記憶體空間,可以看作是當前執行緒所執行的位元組碼的行號指示器,位元組碼解釋器作業時通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、回圈、跳轉、例外處理、執行緒恢復等功能都需要依賴這個計數器來完成,
注意:程式計數器是唯一一個不會出現 OutOfMemoryError 的記憶體區域,它的生命周期隨著執行緒的創建而創建,隨著執行緒的結束而死亡,
Java虛擬機堆疊
每個Java方法在執行時都會創建一個堆疊幀(Java方法執行的記憶體模型),每一個方法從被呼叫到執行完成的程序,就是一個堆疊幀在Java虛擬機堆疊中入堆疊到出堆疊的程序,堆疊是先進后出的資料結構,也就是說,后被呼叫的Java方法會先結束,

上圖就是一個Java虛擬機堆疊的結構,一個Java虛擬機堆疊是由一個個堆疊幀組成的,而每個堆疊幀中都擁有區域變數表、運算元堆疊、動態鏈接、方法回傳地址,
Java虛擬機堆疊可能會出現以下兩種錯誤:
StackOverFlowError:若堆疊的記憶體大小不允許動態擴展,那么當執行緒請求堆疊的深度超過當前Java虛擬機堆疊的最大深度的時候,就拋出StackOverFlowError錯誤,
OutOfMemoryError:如果堆疊的記憶體大小可以動態擴展,如果虛擬機在動態擴展堆疊時無法申請到足夠的記憶體空間,則拋出OutOfMemoryError例外,
區域變數表
主要存放了編譯期可知的各種資料型別(boolean、byte、char、short、int、float、long、double)、物件參考(reference 型別,它不同于物件本身,可能是一個指向物件起始地址的參考指標,也可能是指向一個代表物件的句柄或其他與此物件相關的位置),
運算元堆疊
主要作為方法呼叫的中轉站使用,用于存放方法執行程序中產生的中間計算結果,另外,計算程序中產生的臨時變數也會放在運算元堆疊中,
動態鏈接
主要服務一個方法需要呼叫其他方法的場景,在 Java 源檔案被編譯成位元組碼檔案時,所有的變數和方法參考都作為符號參考(Symbilic Reference)保存在 Class 檔案的常量池里,當一個方法要呼叫其他方法,需要將常量池中指向方法的符號參考轉化為其在記憶體地址中的直接參考,動態鏈接的作用就是為了將符號參考轉換為呼叫方法的記憶體地址的直接參考,

本地方法堆疊
本地方法堆疊與Java虛擬機堆疊作用相似,它們之間的區別是Java虛擬機堆疊為虛擬機執行Java方法服務,而本地方法堆疊則為虛擬機使用到的Native方法服務,本地方法被執行的時候,在本地方法堆疊也會創建一個堆疊幀,用于存放該本地方法的區域變數表、運算元堆疊、動態鏈接、方法回傳地址,
堆
堆是Java虛擬機所管理的記憶體中最大的一塊,Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機啟動時創建,堆的作用就是存放物件實體,幾乎所有物件實體都在這個區域分配記憶體,
Java堆是垃圾收集器管理的主要區域,因此也叫GC堆(Garbage Collected Heap),從記憶體回收的角度(收集器一般采用分代收集演算法),Java堆記憶體可以細分為:新生代和老年代,新生代再細分有:Eden區、Survivor0區、Survivor1區,

根據虛擬機規范,Java堆可以處于物理上的不連續記憶體中,只要邏輯上是連續即可,其大小可以通過-Xmx和-Xms控制,如果在堆中沒有記憶體完成實體分配,并且堆也無法擴展時會拋出OutOfMemoryError例外,
方法區

虛擬機要使用一個類時,它需要讀取并決議.class檔案獲取相關資訊,再將資訊存入到方法區,方法區用于存放類資訊、欄位資訊、方法資訊、常量、靜態變數、即時編譯器編譯后的代碼快取等資料,
《Java 虛擬機規范》只是定義了方法區這個概念和它的作用,在不同的虛擬機實作上,方法區的實作是不同的,JDK1.8之前的方法區實作叫永久代,到了JDK1.8,方法區實作叫元空間,它取代了永久代,元空間與永久代之間最大的區別在于:元空間并不在虛擬機中,而是使用本地記憶體,因此,默認情況下,元空間的大小僅受本地記憶體限制,

元空間 (MetaSpace)替代永久代(PermGen) 的原因如下:
1、永久代受到JVM本身設定的固定大小限制,無法進行調整,而元空間使用的是直接記憶體,受本機可用記憶體的限制,雖然元空間仍舊可能溢位,但是比永久代出現的幾率會更小,
2、永久代的物件是通過FullGC進行垃圾收集,也就是和老年代同時實作垃圾收集,替換成元空間以后,簡化了Full GC,可以在不進行暫停的情況下并發地釋放類資料,同時也提升了GC的性能,
3、在JDK1.8,合并HotSpot和JRockit的代碼時, JRockit從來沒有一個叫永久代的東西, 合并之后就沒有必要額外的設定這么一個永久代的地方了,
本文來自博客園,作者:Yi00,轉載請注明原文鏈接:https://www.cnblogs.com/ayic/p/16842380.html
聊聊技術,聊聊人生,歡迎關注我的公眾號!^_^
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/523163.html
標籤:其他
下一篇:小米開放平臺逆向工程
