運行時數(shù)據(jù)區(qū)
事實上屡谐,JVM在執(zhí)行Java代碼時都會把內(nèi)存分為幾個部分筷登,即數(shù)據(jù)區(qū)來使用魂爪,這些區(qū)域都擁有自己的用途先舷,并隨著JVM進程的啟動或者用戶線程的啟動和結(jié)束建立和銷毀。如下圖大家應該很熟悉滓侍。
程序計數(shù)器(Program Counter Register)
它所占用的內(nèi)存空間比較小蒋川,主要用于當前線程所執(zhí)行的字節(jié)碼的行號指示器,其實很好理解因為當我們線程切換的時候需要記錄當前線程執(zhí)行到什么地方撩笆,下一步該做什么捺球,其實可以類比一下操作系統(tǒng)中的程序計數(shù)器缸浦。由它的作用可想而知它是我們線程私有的一個數(shù)據(jù)區(qū)。
可能觸發(fā)的異常:程序計數(shù)器是在JVM規(guī)范中唯一個不會觸發(fā)OutOfMemoryError(內(nèi)存泄露錯誤氮兵,下文簡稱OOM)裂逐。
虛擬機棧(VM Stack)
它的數(shù)據(jù)結(jié)構(gòu)也就是我們常說的棧結(jié)構(gòu)。每個方法在執(zhí)行的同時都會開辟一段內(nèi)存區(qū)域用于存放方法運行時所需的數(shù)據(jù)泣栈,成為棧幀卜高,一個棧幀包含如:局部變量表、操作數(shù)棧南片、動態(tài)鏈接掺涛、方法出口等信息。其中局部變量表是在編譯期分配空間的疼进,運行期間是不變的薪缆。故而它也是線程私有的。也因為它是棧的結(jié)構(gòu)由棧先進后出的特性方法的執(zhí)行被調(diào)用的先執(zhí)行完后執(zhí)行調(diào)用方伞广。
可能觸發(fā)的異常:
1矮燎、如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常赔癌。
2、如果在動態(tài)擴展內(nèi)存的時候無法申請到足夠的內(nèi)存澜沟,就會拋出OOM異常灾票。單線程下一般不可能被觸發(fā),多數(shù)在多線程的情況下被觸發(fā)OOM異常茫虽。
設(shè)置JVM參數(shù):"-Xss128k"(棧大小為128K)
本地方法棧
本地方法棧和虛擬機棧類似刊苍,不同的是虛擬機棧服務的是Java方法,而本地方法棧服務的是Native方法濒析。在HotSpot虛擬機實現(xiàn)中是把本地方法棧和虛擬機棧合二為一的正什,同理它也會拋出StackOverflowError異常和OOM異常。
堆(heap)
對于堆号杏,Java程序員都知道對象實例以及數(shù)組內(nèi)存都要在堆上分配婴氮。堆不再被線程所獨有而是線程所共享的一塊區(qū)域,它的確是用來存放對象實例盾致,也是垃圾回收GC的主要區(qū)域主经。實際上它還能細分為:新生代(Young Generation)、老年代(Old Generation)庭惜。對于新生代又分為Eden空間罩驻、From Survivor空間、To Survivor空間护赊。惠遏。
可能觸發(fā)的異常:堆申請的空間過大并且每個對象都有GC Root的指向不能被回收砾跃,會拋出OOM異常。
設(shè)置JVM參數(shù):"-Xms128M"(表示初始堆大小128M)节吮、"-Xmx2048M"(表示最大堆大小2048M)
方法區(qū)(Method Area)
它存儲的是已被虛擬機加載的類信息抽高、常量(從JDK7開始已經(jīng)移至堆內(nèi)存中)、靜態(tài)變量等數(shù)據(jù)课锌。它還有一個外號就是永久代(Permanent Generation)但是7及以后都在去掉永久代厨内。在JDK8則是純粹取消了方法區(qū)這個概念,取而代之的是”元空間(Metaspace)
可能觸發(fā)的異常:當方法區(qū)無法滿足內(nèi)存分配需求時渺贤,將拋出OutOfMemoryError異常雏胃。
設(shè)置JVM參數(shù):"-XX:MaxPermSize=256M"(表示方法區(qū)最大內(nèi)存為256M)在JDK8中變?yōu)榱?-XX:MetaspaceSize"和"-XX:MaxMetaspaceSize"來設(shè)置元空間的大小了。