目錄
導讀
上篇博客:【JVM】自動內存管理機制《一》相信你明白了爲什麼內存需要管理:爲了解決有限資源和無限需求的衝突!內存是有限的,但在運行的過程中最大的衝突就是:內存不夠用。 也看了java8的內存模型是分區域的,那麼有沒有想過一個問題:內存爲什麼劃分?還有上篇博客的遺留問題:內存爲什麼要自動管理?如何自動管理的?這一切都是爲了更好的利用和管理內存那麼今天會解決這三個問題
1.jvm虛擬機內存爲什麼劃分區域?劃分原則是什麼?
2.內存爲什麼要自動管理?
3.如何自動管理的?
JVM內存爲什麼劃分區域?
源於生活的智慧:你的家就是你存放物品的區域,你會劃分陽臺,廁所,廚房,臥室,化妝臺等等。你爲什麼劃分呢??很簡單,假想一下:假如你的化妝品放在廚房,鍋放在臥室,牀放在廁所,,,,哇,,,這,,,,amazing啊~~~這會帶來什麼問題???再試想一下,你們家不是就那麼大,假如你們產生的生活垃圾,不處理,不回收,那麼???家裏會怎麼樣?遲早有一天你的家會被垃圾充滿,你就不用進去啦。
JVM內存模型詳細介紹:
線程私有內存區域
(1)程序計數器
說簡單一點就是:一小塊較小內存空間,存着什麼呢?存的是當前線程下一條需要執行的指令的行號,當字節碼解釋器工作是能夠通過改變這個計數器的值來選取下一條需要執行的字節碼指令。在說明一點,各條線程之間計數器互不影響,獨立存儲,程序計數器器內存區域爲 線程私有 的。
注意:在JVM規範中規定:
如果線程執行的是native本地方法,程序計數器中保存的是undefind;
如果線程執行的是不是native方法,則保存的是下一條指令的地址的行號;
由於程序計數器中存儲的數據所佔空間的大小不會隨程序的執行而發生改變,
異常情況:此內存區域是唯一一個在JVM規範中沒有規定任何OutOfMemoryError情況的區域
(2)java虛擬機棧
Java虛擬機棧是Java方法執行的內存模型,(線程私有)每個線程對應自己的虛擬機棧,每個虛擬機棧中存放的是一個個棧幀,每個棧幀對應當前線程中一個個被調用的方法。詳細看下圖的結構
-
局部變量表:用來存儲方法中的局部變量【包括方法中聲明的非靜態變量及函數形參】。對於基礎數據類型的變量,則直接存儲它的值,對於引用類型的變量,則存的是指向對象的引用。局部變量彪的大小在編譯器就確定其大小了,運行期間大小不變
-
操作數棧:棧 典型應用就是對錶達式求值,程序中所有的計算過程都是藉助於操作數棧來完成的
-
指向運行時常量的引用:因爲在方法執行的過程中有可能會用到類中的常量,所以必須要有一個引用指向運行時常量
-
方法返回地址:當一個方法執行完畢之後,要返回之前調用它的地方,因此在棧幀中必須保存一個方法返回地址。
異常情況:在這個區域規定了兩種異常狀況:
- 如果線程請求的棧深入大於虛擬機所允許的深度,將拋出StackOverFlowError異常!
- 如果虛擬機棧可以動態擴展,當擴展到無法申請內存到足夠的內存,就會拋出OutOfMemoryError異常!
(3)本地方法棧
本地方法棧和虛擬機棧所發揮的作用是很相似的,它們之間的區別不過是 虛擬機棧爲虛擬機執行Java方法(字節碼)服務,而本地方法棧則爲虛擬機使用到的Native方法服務。Sun HotSpot 直接就把本地方法棧和虛擬機棧合二爲一。本地方法棧也會拋出StackOverflowError和OutOfMemoryError異常。
異常情況:本地方法棧也會拋出StackOverflowError和OutOfMemoryError異常。
線程公有
(4)Java堆
堆是jvm內存管理的最大的一塊區域,此內存區域的唯一目的就是存放對象的實例,所有對象實例與數組都要在堆上分配內存。堆內也會有劃分:年輕代(8:1:1),老年代
異常情況: 如果在堆中沒有內存完成實例分配,並且堆也無法再擴展時,將拋出OutOfMemoryError異常。
(5)元空間
元空間:是方法區的在HotSpot jvm 中的實現,方法區主要用於存儲類的信息、常量池、方法數據、方法代碼等。方法區邏輯上屬於堆的一部分,但是爲了與堆進行區分,通常又叫“非堆”。元空間的本質和永久代類似,都是對JVM規範中方法區的實現。不過元空間與永久代之間最大的區別在於:元空間並不在虛擬機中,而是使用本地內存。,理論上取決於32位/64位系統可虛擬的內存大小。可見也不是無限制的,需要配置參數。
(6)Java中的(三種類型)常量池
常量池 | 所處區域 | 誕生時間 |
類文件中常量池(The Constant Pool) |
堆 | 編譯時 |
運行時常量池(The Run-Time Constant Pool) | 元空間 | JVM運行時 |
String常量池 | 堆 | 在類加載完成,經過驗證,準備階段之後在堆中生成字符串對象實例,然後將該字符串對象實例的引用值存到string pool中 |
- 類文件中常量池:符號引用和字面量——在編譯階段,每個class都有的,存放的是常量的符號引用。那麼問題來了,符號信息有什麼用呢?是Java虛擬機在執行指令的時候會依賴這些信息
- 運行時常量池:class文件元信息描述,編譯後的代碼數據,引用類型數據,類文件常量池——所謂的運行時常量池就是用來動態獲取類信息的入口。運行時常量池是在類加載完成之後,將每個class常量池中的符號引用值轉存到運行時常量池中,也就是說,每個class都有一個運行時常量池,類在解析之後,將符號引用替換成直接引用,與全局常量池中的引用值保持一致。
- 字符串常量池:string pool中存的是引用值而不是具體的實例對象,具體的實例對象是在堆中開闢的一塊空間存放的)。 在HotSpot VM裏實現的string pool功能的是一個StringTable類,它是一個哈希表,裏面存的是駐留字符串(也就是我們常說的用雙引號括起來的)的引用(而不是駐留字符串實例本身),也就是說在堆中的某些字符串實例被這個StringTable引用之後就等同被賦予了”駐留字符串”的身份。這個StringTable在每個HotSpot VM的實例只有一份,被所有的類共享。
內存爲什麼要自動管理?
優點:增加了程序的可靠性,減小了內存泄露和野指針的情況,提高了程序員的效率,從手動變爲自動
缺點:程序員無法控制GC的時間
判斷哪些內存需要回收需要耗費系統開銷
邏輯上的內存泄露依然會存在
這也是爲什麼我們要了解掌握JVM內存的自動管理機制,方便排查問題,調優
如何自動管理內存?
解決第三個問題,第三個問題有些複雜,這裏籠統的介紹下,詳細請看下篇博客:如何自動管理的?誰管理的?
接下來按下面的順序講述:
1.內存回收機制
* 對象存活判定算法
* 垃圾收集算法
* 垃圾收集器(對垃圾收集算法的實現)
2.內存分配與回收策略
* 原則
小結
今天主要解決了兩個問題:1.jvm虛擬機內存爲什麼劃分區域以及各區域分別是什麼作用?2.內存爲什麼要自動管理?,希望大家有所收穫,關於第三個問題,請點擊查看看:【JVM】自動內存管理機制《三》 ,習慣的話,給小編點個贊,作爲我繼續前進的動力,感謝哦!