Java的內(nèi)存結(jié)構(gòu):
JVM內(nèi)存結(jié)構(gòu)主要有三大塊:堆內(nèi)存、方法區(qū)和棧悔详。堆內(nèi)存是JVM中最大的一塊由年輕代和老年代組成晰韵,而年輕代內(nèi)存又被分成三部分,Eden空間拆魏、From Survivor空間盯桦、To Survivor空間,默認情況下年輕代按照8:1:1的比例來分配;
其中Survivor區(qū)間中渤刃,某一時刻只有其中一個是被使用的拥峦,另外一個留做垃圾收集時復(fù)制對象用,在Young區(qū)間變滿的時候卖子,minor GC就會將存活的對象移到空閑的Survivor區(qū)間中略号,根據(jù)JVM的策略,在經(jīng)過幾次垃圾收集后,任然存活于Survivor的對象將被移動到Tenured區(qū)間玄柠。
Tenured:年老代
Tenured區(qū)主要保存生命周期長的對象氛琢,一般是一些老的對象,當(dāng)一些對象在Young復(fù)制轉(zhuǎn)移一定的次數(shù)以后随闪,對象就會被轉(zhuǎn)移到Tenured區(qū),一般如果系統(tǒng)中用了application級別的緩存骚勘,緩存中的對象往往會被轉(zhuǎn)移到這一區(qū)間铐伴。
方法區(qū)存儲類信息、常量俏讹、靜態(tài)變量等數(shù)據(jù)当宴,是線程共享的區(qū)域,為與Java堆區(qū)分泽疆,方法區(qū)還有一個別名Non-Heap(非堆)户矢;棧又分為java虛擬機棧和本地方法棧主要用于方法的執(zhí)行。
Perm:持久代
Perm代主要保存class,method,filed等對象殉疼,這部門的空間一般不會溢出梯浪。
java.lang.OutOfMemoryError : PermGen space 的錯誤,造成這個錯誤的很大原因就有可能是每次都重新部署瓢娜,但是重新部署后挂洛,類的class沒有被卸載掉,這樣就造成了大量的class對象保存在了perm中眠砾,這種情況下虏劲,一般重新啟動應(yīng)用服務(wù)器可以解決問題。
在通過一張圖來了解如何通過參數(shù)來控制各區(qū)域的內(nèi)存大小
控制參數(shù)
-Xms設(shè)置堆的最小空間大小褒颈。
-Xmx設(shè)置堆的最大空間大小柒巫。
-XX:NewSize設(shè)置新生代最小空間大小。
-XX:MaxNewSize設(shè)置新生代最大空間大小谷丸。
-XX:PermSize設(shè)置永久代最小空間大小堡掏。
-XX:MaxPermSize設(shè)置永久代最大空間大小。
-Xss設(shè)置每個線程的堆棧大小淤井。
Java中的內(nèi)存分配:
- 棧:存放局部變量布疼,線程私有,生命周期和線程相同币狠,棧由一系列幀組成(因此Java棧也叫做幀棧)游两,每一次方法調(diào)用創(chuàng)建一個幀,并壓棧
- 堆:存放所有new出來的東西漩绵,和程序開發(fā)密切相關(guān)贱案,應(yīng)用系統(tǒng)對象都保存在Java堆中,所有線程共享Java堆,GC管理的主要區(qū)域
- 方法區(qū):被虛擬機加載的類信息宝踪、常量侨糟、靜態(tài)常量:類型的常量池,字段瘩燥,方法信息秕重,方法字節(jié)碼,通常和永久區(qū)(Perm)關(guān)聯(lián)在一起厉膀。
- 程序計數(shù)器(和系統(tǒng)相關(guān)):每個線程擁有一個PC寄存器溶耘,在線程創(chuàng)建時創(chuàng)建指向下一條指令的地址
- 本地方法棧
在Java虛擬機規(guī)范中,對這個區(qū)域規(guī)定了兩種異常情況:
(1)如果線程請求的棧深度太深服鹅,超出了虛擬機所允許的深度凳兵,就會出現(xiàn)StackOverFlowError(比如無限遞歸。因為每一層棧幀都占用一定空間企软,而 Xss 規(guī)定了棧的最大空間庐扫,超出這個值就會報錯)
(2)虛擬機棧可以動態(tài)擴展仗哨,如果擴展到無法申請足夠的內(nèi)存空間形庭,會出現(xiàn)OOM