java痴和堆_JAVA虚拟机理解 - 爱笑的痴迷者的个人空间 - OSCHINA - 中文开源技术交流社区...
JVM定義:
JVM(Java Virtual Machine),是一種運行Java程序的軟件實現(xiàn),是虛擬的機器。Java程序與平臺無關(guān),它直接在虛擬機中運行。
JVM運行過程:
JVM將內(nèi)存分劃如下五個區(qū)域:
1、方法區(qū);2、堆區(qū);3、虛擬機棧;4、本地方法棧;5、程序計數(shù)器;
方法區(qū)(Method Area):
JVM使用類裝載器裝載某個類時,會找到相應(yīng)的class文件,并讀取該文件內(nèi)容信息,以及將存儲到方法,最后返回一個class實例。
方法區(qū)存放內(nèi)容:1、類的全限定名(類的全路徑名);2、類的直接超類的權(quán)全限定名(如果這個類是Object,則它沒有超類);3、類的類型(類或接口);4、類的訪問修飾符,public,abstract,final等;5、類的直接接口全限定名的有序列表;6、常量池(字段,方法信息,靜態(tài)變量,類型引用(class))等;
方法區(qū)是全局共享的,但是它也是線程安全的。在一定條件下它也會被GC。當(dāng)方法區(qū)使用的內(nèi)存超過它允許的大小時,就會拋出OutOfMemory:PermGen Space異常。產(chǎn)生該錯誤的原因大都出于以下原因:JVM內(nèi)存過小、程序不嚴密,產(chǎn)生了過多的垃圾。
JVM方法區(qū)的相關(guān)參數(shù),最小值:--XX:PermSize;最大值:--XX:MaxPermSize。
堆區(qū)(Heap?Area):
一個運行時數(shù)據(jù)區(qū),類的實例(new創(chuàng)造的對象)從中分配空間,它的管理是由垃圾回收來負責(zé)的。堆區(qū)由所有線程共享,且用來存儲對象實例及數(shù)組值。
對于堆區(qū)大小,可以通過參數(shù)-Xms和-Xmx來控制:
-Xms為JVM啟動時申請的最新head內(nèi)存,默認為物理內(nèi)存的1/64但小于1GB;
-Xmx為JVM可申請的最大Head內(nèi)存,默認為物理內(nèi)存的1/4但小于1GB;
當(dāng)剩余堆空間小于40%時,JVM會增大Head到-Xmx大小,可通過-XX:MinHeapFreeRadio參數(shù)來控制這個比例;
當(dāng)空余堆內(nèi)存大于70%時,JVM會減少Head大小到-Xms指定大小,可通過-XX:MaxHeapFreeRatio來指定這個比例。
虛擬機棧(JVM Stacks):
虛擬機棧是線程私有的,它的生命周期與線程相同。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模式:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(Statck Frame),用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每個方法從調(diào)用至執(zhí)行完成的過程,就對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程。
局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型(boolean、btye、char、short、int、float、long、double)、對象引用(reference類型,它不等于對象本身,可能是一個指向?qū)ο笃鹗嫉刂返囊弥羔?#xff0c;也可能是指向一個代表對象的句柄或其他與此對象相關(guān)的位置)和returnAddress類型(指向了一個字節(jié)碼指令的地址)
其中64位長度的long和double類型的數(shù)據(jù)會占用2個局部變量空間(Slot),其他都是1個Slot。局部變量表所需的內(nèi)存空間是在編譯期間完成分配,當(dāng)進入一個方法時,這個方法需要在幀中分配多大的局部變量空間是完全確定的,在方法運行期間不會改變局部變量表的大小。
虛擬機棧中定義了兩種異常,如果線程請求的棧深度大于虛擬機所允許深度,則拋出StatckOverFlowError(棧溢出);不過多數(shù)Java虛擬機都允許動態(tài)擴展虛擬機棧的大小(有少部分是固定長度的),所以線程可以一直申請棧,直到內(nèi)存不足,則會拋出OutOfMemoryError(內(nèi)存溢出)。
本地方法棧(Native Method Stack):
本地方法棧用于支持native方法的執(zhí)行,存儲了每個native方法調(diào)用的狀態(tài)。本地方法棧和虛擬機方法棧運行機制一致,它們唯一的區(qū)別就是,虛擬機棧是執(zhí)行Java方法的,而本地方法棧是用來執(zhí)行native方法的,在很多虛擬機中,會將本地方法棧與虛擬機棧放在一起使用。
程序計數(shù)器(Program Counter Register):
一個比較小的內(nèi)存空間,可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機的概念模型里(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實現(xiàn)),字節(jié)碼解釋器工作時,會通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。
由于Java虛擬機的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,在任何一個確定的時刻,一個處理器(對于多核處理器來說是一個內(nèi)核)都只會執(zhí)行一個線程中的指令。因此,為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每條線程都需要有一個獨立的程序計數(shù)器,每條線程之間計數(shù)器互不影響,獨立存儲。
如果線程正在執(zhí)行的是一個Java方法,這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令地址;如果正在執(zhí)行的是Native方法,這個計數(shù)器的值為空(Undefined)。此內(nèi)存區(qū)域是唯一一個在Java虛擬機規(guī)范中沒有任何OutOfMemoryError的區(qū)域。
JAVA對象訪問方式
一個Java的引用訪問涉及到3個內(nèi)存區(qū)域:JVM棧、堆、方法區(qū)。
以最簡單的本地變量引用,Object obj = new Object()為例:
類變量(方法區(qū)):獨立于方法之外的變量,用 static 修飾;
實例變量(堆):獨立于方法之外的變量,不過沒有 static 修飾;
局部變量(棧):類的方法中的變量;
public class Test{
static int a=0; // 類變量
String b="hello world"; // 實例變量
public void method(){
int c =0; // 局部變量
}
}
Object obj表示一個本地引用,存儲在JVM棧的本地變量表中,表示一個reference類型數(shù)據(jù);
new Object()作為實例對象數(shù)據(jù)存儲在堆中;
堆中還記錄了能夠查詢到此Object對象的類型數(shù)據(jù)(接口、方法、field、對象類型等)的地址,實際的數(shù)據(jù)則存儲在方法區(qū)中;
在Java虛擬機規(guī)范中,只規(guī)定了指向?qū)ο蟮囊?#xff0c;對于通過reference類型引用訪問具體對象的方式并未做規(guī)定,不過目前主流的實現(xiàn)方式只要有兩種:
1)、句柄訪問:通過句柄訪問的實現(xiàn)方式中,JVM堆中會劃分單獨一塊內(nèi)存區(qū)域作為句柄池,句柄池中存儲了對象實例數(shù)據(jù)(在堆中)和對象類型數(shù)據(jù)(在方法區(qū)中)的指針。這種實現(xiàn)方法由于用句柄表示地址,因此十分穩(wěn)定。
2)、指針訪問:通過直接指針訪問的方式中,reference中存儲的就是對象在堆中的實際地址,在堆中存儲的對象信息中包含了在方法區(qū)中的相應(yīng)類型數(shù)據(jù)。這種方法最大的優(yōu)勢是速度快,在HotSpot虛擬機中用的就是這種方式。
總結(jié)
以上是生活随笔為你收集整理的java痴和堆_JAVA虚拟机理解 - 爱笑的痴迷者的个人空间 - OSCHINA - 中文开源技术交流社区...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CUDA: GPU高性能运算
- 下一篇: C与CUDA混合编程的配置问题