Java內(nèi)存區(qū)域與內(nèi)存溢出異常

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 異常。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容