JVM內存劃分和GC機制

最近看了有關Java虛擬機(Java Virtual Machine)的內存劃分的資料。整理一下。

一、數據存儲初識:
三種常見的數據存儲方式:(三者都位於RAM中,有區別)
* RAM: Random Access Memory隨機存儲器
這裏寫圖片描述
三者的區別:
1) Stack是通過“堆棧指針”來獲取處理器的直接支持。
堆棧指針向下移動,會創建新的內存。
堆棧指針向上移動,會釋放一些內存。
這種存儲方式的優點:
a. 存儲速度快,僅次於CPU寄存器。
b. Java編譯器必須知道要保存的數據的長度以及存在時間
缺點:
a. 限制了程序的靈活性
b. 一般Java對象的引用儲存在其中,而對象不存儲在其中。
2) Heap
相比於Stack優點:
a. 編譯器既無需知曉數據的存在時間(數據要保留多久),又無需知曉數據的大小(數據所需的存儲空間)
b. 在創建對象時,只需要使用new命令即可
缺點:
在堆中分配存儲控件會花費更多的時間,這是Java的性能不佳的重要原因之一。
3) Static 是用static關鍵字修飾的,靜態存儲的位置固定的,有且只有一份。在程序運行時可以隨時被調用。

二、JVM中的數據存儲機制和C++中的存儲機制的對比。
在C++中,對象是可以在堆棧(Stack)中創建的。堆棧的特點是要求給定要存儲數據的大小、存留時間長短。這種存儲方式具有Stack的所有優點和缺點。如果,將C++對象(又稱爲結構體)存儲在創建的”內存堆(Heap)”中,速度會慢很多。
下面以C++內存堆類比Java堆:
* 這種C++內存堆是一個大的內存池,要求必須進行循環使用。
可以把C++的內存堆(Heap)看做一塊場地。在這塊場地內,每個對象不斷的監視自己的地盤,它們可能在某個時間不在佔用所佔有的控件,即被釋放,留下了一個空白區域,下次要存儲別的新對象時,先要從整個存儲區(場地)中找出空白區,然後存放進去。(內存搜索費時費力!!!)

三、分代方式管理堆
由於內存搜索性能低下,爲了緩解這個問題,SUN採用的是分代管理堆內存。這是一種分區域管理(類似於圖書館的分類管理方法),來減小要掃描的區域,以提高性能的方法。
基本原理:
1. 分代管理中,代分爲年輕代、年老代
2. 年輕代分爲三個區:一個Eden區(又稱爲from),兩個Survivor區(又稱爲to)
3. 一般情況下,新創建的對象會被分配到Eden區(一些大對象會做特殊處理)。這些對象經過第一次Minor GC後,存活着的對象將會移動到Survivor區。此時此對象的年齡增長1歲(每通過一次Minor GC後存活下來年齡就增長1歲),年齡增長到一定程度後(>=n),此對象就會被移動到年老代。
4. 通過Minor GC死去的對象即被釋放的對象將會被作爲垃圾回收。
* 注:因爲年輕代中80%的對象基本上是”朝生暮死”,所以年輕代中的垃圾回收算法是複製算法。
步驟圖示:
首次創建對象:
這裏寫圖片描述
第一次Minor GC
這裏寫圖片描述
第二次Minor GC
這裏寫圖片描述
若干次Minor GC後
這裏寫圖片描述

關於複製算法:
基本思想:將內存一分爲二。先用其中一半,當這一半存滿後,檢查其中存活的,複製到另一半,清空此半部分。此種算法不會產生碎片。
其他主要的幾種算法:
(1).Tracing算法與Compat算法
Trancing算法是一種追蹤標記算法。用於追蹤和標記活動對象。在所有標記結束後,開始清除過程。清除死去的對象後,存儲區變成了一個不連續的區域,此時使用Compat算法,將活動的象移動到一起,連續排列。
(2).Generational算法
主要是針對Copy算法多次複製長時間存活的對象進行了優化,缺點是程序有停頓。
(3).Adapter算法

四、Android Studio中的配置(gradle.properties)
1.JVM運行時堆的大小設置:
-Xms 堆的最小值
-Xmx 堆的最大值
2.年輕代堆控件大小設置
-XX:NewSize 年輕代堆最小值
-XX:MaxNewSize 年輕代堆最大值
-XX:NewRadio 年輕代堆在堆中所佔的比率
-XX:SurvivorRadio 年輕代堆中Survivor所佔的比率
3.永久代大小設置
-XX:MaxPermSize
4.年老代的最小年齡(年輕代的最大年齡,用來區分一個存活對象是否進入年老代)
-XX:MaxTemuringThreshold

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章