標籤:
文章出處(引用):http://topic.csdn.net/u/20090602/10/bd9d4ba2-dbeb-49b3-8651-67c5de2b228a.html
,JVM主要包括兩個子系統和兩個組件。兩個子系統分別是Class loader子系統和Execution engine(執行引擎) 子系統;兩個組件分別是Runtime data area (運行時資料區域)組件和Native interface(本地介面)組件。
Class loader子系統的作用:
根據給定的全限定名類名(如 java.lang.Object)來裝載class檔案的內容到 Runtime data area中的method area(方法地區)。Java程式員可以extends java.lang.ClassLoader類來寫自己的Class loader。
Execution engine子系統的作用:
執行classes中的指令。任何JVM specification實現(JDK)的核心都是Execution engine,不同的JDK例如Sun 的JDK 和IBM的JDK好壞主要就取決於他們各自實現的Execution engine的好壞。
Native interface組件:
與native libraries互動,是其它程式設計語言互動的介面。當調用native方法的時候,就進入了一個全新的並且不再受虛擬機器限制的世界,所以也很容易出現JVM無法控制的native heap OutOfMemory。
Runtime Data Area組件:
這就是我們常說的JVM的記憶體了。它主要分為五個部分——
1、Heap (堆):一個Java虛擬執行個體中只存在一個堆空間
2、Method Area(方法地區):被裝載的class的資訊儲存在Method area的記憶體中。當虛擬機器裝載某個類型時,它使用類裝載器定位相應的class檔案,然後讀入這個class檔案內容並把它傳輸到虛擬機器中。
3、Java Stack(java的棧):虛擬機器只會直接對Java stack執行兩種操作:以幀為單位的壓棧或出棧
4、Program Counter(程式計數器):每一個線程都有它自己的PC寄存器,也是該線程啟動時建立的。PC寄存器的內容總是指向下一條將被執行指令的餓地址,這裡的地址可以是一個本地指標,也可以是在方法區中相對應於該方法起始指令的位移量。
5、Native method stack(本地方法棧):儲存native方法進入地區的地址
以上五部分只有Heap 和Method Area是被所有線程的共用使用的;而Java stack, Program counter 和Native method stack是以線程為粒度的,每個線程獨自擁有自己的部分。
Sun的JVM Generational Collecting(記憶體回收)原理是這樣的:把對象分為年青代(Young)、年老代(Tenured)、持久代(Perm),對不同生命週期的對象使用不同的演算法。(基於對對象生命週期分析)
如所示,為Java堆中的各代分布。
1. Young(年輕代)
年輕代分三個區。一個Eden區,兩個Survivor區。大部分對象在Eden區中產生。當Eden區滿時,還存活的對象將被複製到Survivor區(兩個中的一個),當這個Survivor區滿時,此區的存活對象將被複製到另外一個Survivor區,當這個Survivor去也滿了的時候,從第一個Survivor區複製過來的並且此時還存活的對象,將被複製年老區(Tenured。需要注意,Survivor的兩個區是對稱的,沒先後關係,所以同一個區中可能同時存在從Eden複製過來 對象,和從前一個Survivor複製過來的對象,而複製到年老區的只有從第一個Survivor去過來的對象。而且,Survivor區總有一個是空的。
2. Tenured(年老代)
年老代存放從年輕代存活的對象。一般來說年老代存放的都是生命期較長的對象。
3. Perm(持久代)
用於存放靜態檔案,如今Java類、方法等。持久代對記憶體回收沒有顯著影響,但是有些應用可能動態產生或者調用一些class,例如Hibernate等,在這種時候需要設定一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=進行設定。
舉個例子:當在程式中產生對象時,正常對象會在年輕代中分配空間,如果是過大的對象也可能會直接在年老代產生(據觀測在運行某程式時候每次會產生一個十兆的空間用收發訊息,這部分記憶體就會直接在年老代分配)。年輕代在空間被分配完的時候就會發起記憶體回收,大部分記憶體會被回收,一部分倖存的記憶體會被拷貝至Survivor的from區,經過多次回收以後如果from區記憶體也分配完畢,就會也發生記憶體回收然後將剩餘的對象拷貝至to區。等到to區也滿的時候,就會再次發生記憶體回收然後把倖存的對象拷貝至年老區。
通常我們說的JVM記憶體回收總是在指堆記憶體回收,確實只有堆中的內容是動態申請分配的,所以以上對象的年輕代和年老代都是指的JVM的Heap空間,而持久代則是之前提到的Method Area,不屬於Heap。
個參數意義:
引用:http://longdick.iteye.com/blog/468368
在JVM啟動時,就已經保留了固定的記憶體空間給Heap記憶體,這部分記憶體並不一定都會被JVM使用,但是可以確定的是這部分保留的記憶體不會被其他進程使用。這部分記憶體大小由 -Xmx 參數指定。
而另一部分記憶體在JVM啟動時就分配給JVM,作為JVM的初始Heap記憶體使用量。影響這個的參數是 -Xms ,如果 -Xms 指定的值比-Xmx 的小,那麼兩者的差值就是Virtual記憶體值。隨著程式的運行,Eden區、 Tenured區和Perm區會逐漸使用保留的Virtual空間。
如果沒有具體指定,初始和最大堆記憶體將根據機器的記憶體計算得出。參數DefaultInitialRAMFraction 和DefaultMaxRAMFraction 會影響最終的結果,如下表所示:
Formula Default
| initial heap size |
memory / DefaultInitialRAMFraction |
memory /64 |
| maximum heap size |
MIN(memory / DefaultMaxRAMFraction, 1GB) |
MIN(memory/ 4, 1GB) |
可以看到堆記憶體預設值最大不會超過1G。
JVM會根據堆記憶體的使用方式自動決定何時擴張和縮減實際堆記憶體的大小,可以用VM參數 -XX:MinHeapFreeRatio=<minimum> 和 -XX:MaxHeapFreeRatio=<maximum> 使用堆記憶體空閑百分比來定義,一般在32位機器上的預設值如下:
Parameter Default Value
MinHeapFreeRatio |
40 |
MaxHeapFreeRatio |
70 |
-Xms |
3670k |
-Xmx |
64m |
當空閑堆記憶體所佔堆記憶體百分比低於40%,JVM就會試圖擴張堆記憶體空間;當空閑堆記憶體所佔堆記憶體百分比高於70%,JVM就會試圖壓縮堆記憶體空間。
ps:以上預設值在不同平台會有不同的值,如果是64位系統,這些值一般需要擴張30%,來容納在64位系統下變大的對象。
加上-XX:NewRatio=3 意味著 young(年輕代) 和 tenured(終生代)的比率是1:3,也就是說,eden區和survivor區容量之和將佔總堆記憶體的1/4。
加上-XX:SurvivorRatio=6設定eden區和 其中一個survivor space的比率是1:6,也就是說,其中一個survivor space占年輕代1/8的容量 (可以想想為什麼不是1/7)。
另外還有 -XX:NewSize -XX:MaxNewSize 指定年輕代的初始值和最大值。
32位系統下預設值如下:
Default Value Parameter Client JVM Server JVM
NewRatio |
8 |
2 |
NewSize |
2228K |
2228K |
MaxNewSize |
not limited |
not limited |
SurvivorRatio |
32 |
32 |
【轉】JVM記憶體模型