Java 虛擬機所管理的內(nèi)存包括以下幾個運行時數(shù)據(jù)區(qū)域
一、程序計數(shù)器
特點:
- 線程私有
- 當(dāng)前線程的行號指示器
- 唯一一個在Java 虛擬機規(guī)范中沒有規(guī)定任何OOM情況的區(qū)域
二、Java 虛擬機棧
特點:
- 線程私有
- 存放各種基本數(shù)據(jù)類型(boolean、byte、char、short、int、float、long、double)、對象引用(reference類型)
- 使用-Xss 參數(shù)減少棧內(nèi)存容量
異常:
- 如果線程請求的棧深度大于虛擬機所允許的深度,將拋出 StackOverflowError異常
- 如果虛擬機可以動態(tài)擴展,如果擴展時無法申請到足夠的內(nèi)存,就會報拋出OutOfMemoryError異常
三、本地方法棧
特點:
- 線程私有
- 與虛擬機棧非常相似,虛擬機棧為虛擬機執(zhí)行Java方法服務(wù),本地方法棧則為虛擬機使用Native 方法服務(wù)。
異常:
- 與虛擬機棧一樣,也會拋出 StackOverflowError 和 OutOfMemoryError 異常。
四、Java 堆
特點:
- 線程共享
- 存放對象實例
- Java 堆是垃圾收集器管理的主要區(qū)域,因此很多時候也被稱為“GC 堆”
- 從內(nèi)存回收角度來,由于現(xiàn)在收集器基本都采用分代收集算法,所以Java 堆中還可以細(xì)分為:新生代和老年代;再細(xì)致一點的有Eden 空間、From Survivor空間、To Survivor 空間等。
- 從內(nèi)存分配角度來看,線程共享的Java 堆中可能劃分出多個線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer,TLAB)。
- Java 堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯上是連續(xù)的即可。
- 在實現(xiàn)時,既可以實現(xiàn)成固定大小的,也可以是可擴展的(通過 -Xmx 和 -Xms 控制)
- 新生代和老年代內(nèi)存比例默認(rèn)為 1 : 2
- 新生代中內(nèi)存比例默認(rèn)為 Eden : From : To = 8 : 1 : 1
堆內(nèi)存參數(shù)調(diào)整:
- java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
- -Xmx3550m:設(shè)置JVM最大可用內(nèi)存為3550M。
- -Xms3550m:設(shè)置JVM促使內(nèi)存為3550m。此值可以設(shè)置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內(nèi)存。
- -Xmn2g:設(shè)置年輕代大小為2G。整個JVM內(nèi)存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統(tǒng)性能影響較大,Sun官方推薦配置為整個堆的3/8。
- -Xss128k:設(shè)置每個線程的堆棧大小。JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整。在相同物理內(nèi)存下,減小這個值能生成更多的線程。但是操作系統(tǒng)對一個進(jìn)程內(nèi)的線程數(shù)還是有限制的,不能無限生成,經(jīng)驗值在3000~5000左右。
- java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
- -XX:NewRatio=4:設(shè)置年輕代(包括Eden和兩個Survivor區(qū))與年老代的比值(除去持久代)。設(shè)置為4,則年輕代與年老代所占比值為1:4,年輕代占整個堆棧的1/5
- -XX:SurvivorRatio=4:設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的大小比值。設(shè)置為4,則兩個Survivor區(qū)與一個Eden區(qū)的比值為2:4,一個Survivor區(qū)占整個年輕代的1/6
- -XX:MaxPermSize=16m:設(shè)置持久代大小為16m。
- -XX:MaxTenuringThreshold=0:設(shè)置垃圾最大年齡。如果設(shè)置為0的話,則年輕代對象不經(jīng)過Survivor區(qū),直接進(jìn)入年老代。對于年老代比較多的應(yīng)用,可以提高效率。如果將此值設(shè)置為一個較大值,則年輕代對象會在Survivor區(qū)進(jìn)行多次復(fù)制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。
異常:
- 如果在堆中沒有內(nèi)存完成實例分配,并且堆也無法再擴展時,將會拋出OutOfMemoryError 異常
五、方法區(qū)
特點:
- 線程共享
- 存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。
- jdk 1.8 后改為 Metapace 元數(shù)據(jù)區(qū)域
異常:
- 當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時,將拋出OutOfMemoryError 異常。
六、運行時常量池
特點:
- 線程共享
- 是方法區(qū)的一部分
- Class 文件中除了有類的版本、字段、方法、接口等描述信息外、還有一項信息是常量池,用于存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運行時常量池中存放
異常:
- 運行時常量池是方法區(qū)的一部分,受到方法區(qū)內(nèi)存的限制,當(dāng)常量池?zé)o法再申請到內(nèi)存時會拋出 OutOfMemoryError 異常。