內存管理機制-內存模型與對象的訪問

 

RoadMap

 

虛擬機中的邏輯結構

虛擬機中的內存結構根據虛擬機規範劃分出了五個經常使用區域,這些區域各自有各自的用途,有些隨用戶線程而存在,有些則隨虛擬機進程而存在。 
五個區域分別爲,虛擬機棧,本地方法棧,程序計數器,堆,方法區java

 

程序計數器 (Program Counter Register, PCR)

程序計數器是隨線程而生的,它是線程獨立的,用來記錄當前線程的字節碼與指令,保證下一次線程喚醒以後,能回到正確的執行位置,說白了就是線程喚醒能繼續執行。 
程序計數器是一塊很是小的內存區域,也是惟一一個沒有規定任何OutOfMemoryError的區域算法

虛擬機棧 (Virtual Machine Stack, VM Stack)

虛擬機棧也是線程私有的,它描述了Java方法執行的內存模型:每一個方法被執行是都會建立一個幀棧(Stack Frame) 用於存儲 局部變量表 操做數棧 動態連接 方法出口。每個方法被調用直至執行完成的過程,就是對應着一個幀棧在虛擬機棧中從入棧到出棧的過程。 
局部變量表存放了編譯期可知的基本類型和引用類型。 
在這個區域中,虛擬機規範規定了兩種異常狀況,StackOverflowError:當線程請求棧的深度大於虛擬機容許的深度,將會拋出此異常。 OutOfMemoryErro:當虛擬機棧在動態擴展長度時,沒法申請到足夠內存時將會拋出此異常數組

本地方法棧 (Native Method Stack, NM Stack)

本地方法棧與虛擬機棧發揮的做用很是相似,主要是爲本地方法服務,虛擬機棧是爲Java 方法服務的。 有些虛擬機實現 如 HotSpot 已經將NM Stack 和VM Stack 合二爲一了函數

 

堆 (Heap)

heap 是java 虛擬機管理的內存中最大的一塊,也是線程共享的。在虛擬機啓動時 自動建立。 
除了JIT編譯和逃逸分析技術下的對象,絕大多數的對象實例和數組都在堆上分配。 
同時 堆也是 垃圾收集器(Garbage Collection)主要工做的區域。 
若是堆中沒有可分配的內存空間會拋出OutOfMemoryError性能

方法區

方法區與堆同樣 是線程共享的,用於存儲常量,靜態變量,加載的類信息,即時編譯的代碼數據塊。雖然說 虛擬機規範把方法區化爲堆的一部分,它卻又一個別名non-heap,有意把它和堆區分開了,有些地方也把這地方稱爲,永久代,主要是由於把GC收集擴展至這個區域了或者說用永久代來實現方法區的功能。 
當方法去沒法知足內存分配需求時,將會拋出OutOfMemoryError 
方法去主要存有: 
*類信息 
*類變量 
*類型常量池 
*方法信息 
String常量池即是其中之一。ui

直接內存

直接內存(Direct Memory)並非虛擬機運行時數據區的一部分,也不是Java 
虛擬機規範中定義的內存區域,可是這部份內存也被頻繁地使用,並且也可能致使 
OutOfMemoryError 異常出現,因此咱們放到這裏一塊兒講解。 
在JDK 1.4 中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel) 
與緩衝區(Buffer)的I/O 方式,它可使用Native 函數庫直接分配堆外內存,然 
後經過一個存儲在Java 堆裏面的DirectByteBuffer 對象做爲這塊內存的引用進行 
操做。這樣能在一些場景中顯著提升性能,由於避免了在Java 堆和Native 堆中來 
回覆制數據。spa

堆中的分代劃分

heap 中內存劃分基於分代思想 主要分爲 新生代,老年代和存活區。 線程

新生代 Eden

大多數狀況下,對象在新生代中分配。當Eden區沒有足夠的空間的時候會發起一次MinorGC指針

老年代 Old Generation

大對象直接進入老年代,所謂大對象就是指須要大量連續內存空間的Java 對象,如數組,字符串等。 
同時基於分代思想,虛擬機給每一個對象定義了一個對象年齡。當對象在Eden區通過MinorGC後還生存下來後,會被移動到Suivior Space中並記爲年齡爲1,而且在Suivior Space 每通過一次GC後 對其中存活的對象年齡加1,當對象年齡超過必定的閾值(默認爲15)時,將會被移動到老年代。對象

存活區 Suivivor Space

存活區有點像青年代,用於那些新生代存活下來而未到達老年代的對象。 
同時 存活區分爲From,to 兩塊空間相同的區域,做爲複製回收算法的區域

若是隻是按照對象年齡閥值來判斷是否須要移動到老年代,難以應付多變的內存狀況,加入在存活區有着很是大量的年輕對象(2,3,4,5,6,7歲等)以致於 存活區內存不太夠用的狀況。對於這種狀況,survivor有一個動態年齡斷定。在存活區中的相同年齡的全部對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象就直接進入老年代。

對象訪問方式

Object obj = new Object() 
Object obj 聲明瞭一個引用對象 
new Object() 在堆中開闢了空間並生成對象 
所謂對象的訪問方式是指,引用類型obj如何定位到堆中的具體對象Object()的。

虛擬機中主流的方式有兩種直接指針和句柄池

句柄池

若是使用句柄訪問方式,堆中會劃分出一小塊內存做爲句柄池,reference存儲的是對象的句柄地址,而句柄中包含了對象實例數據和各自數據的具體地址信息。優勢在於,reference存儲的是穩定的句柄地址,在對象被移動時,只會改變句柄中的實例數據指針,reference自己不須要改變。 

直接指針

若是使用餓了直接指針訪問,reference中直接存儲了對象的地址。次方式的優勢在於節約對象訪問方式,對於頻繁的訪問對象,直接指針節約了一個層級的訪問時間。 

相關文章
相關標籤/搜索