JAVA內存區域與內存溢出異常總結概況

Java 7 VM:hotspot VM

java8 VM:hotspot VM(吸收了JRockit VM的部分優點)

內存溢出:簡單的說就是在創建對象或其它行爲申請不到需要的內存大小(申請內存大於實際內存)

內存泄露:簡單的說就是所創建的實例化對象由於種種原因未被gc回收導致內存不足(實例化對象填滿了內存空間)

新生代與老年代:剛創建的對象數據一般都是屬於新生代(有些較大的爲了減少從新生代到老年代的數據拷貝回直接進入老年代),當經歷了15次gc(對象數據的age)依舊沒有被回收時就會進入老年代;除此之外如果老年代中有過半的對象數據age在同一水平,那麼新生代進入老年代的標準就可以不再是15,而是這一過半的水平。

一、內存區域的劃分:

    (一)、程序計數器:字節碼解釋器通過改變計算器的值來選取所要運行的字節碼指令,並由計算器記錄字節碼指令的地址;所佔有的內存較小,由於cpu每次只會處理一條線程(即便是在並行的情況下,進程也是同理,看上去是多個軟件同時運行,實則是根據具體的使用情況斷斷續續的通過佔用cpu進行運作),一般不會產生內存溢出或泄露。

    (二)、Java虛擬機棧:用於存放對象的引用;在Java中,虛擬機棧(用於執行Java方法)與本地方法棧(用於執行Native方法),如果沒有設置大小則會自動擴容。

    (三)、Java堆:與棧相對應,用於存放對象具體的數據,主要可以劃分爲新生代和老年代(堆=新生代+老年代);是垃圾回收的主要區域,因此也被稱爲“GC堆”(垃圾堆),所有線程所共享。

    (四)、方法區:用於存放類信息、常量、靜態變量以及編譯時所產生的數據,這個區域也被人稱之爲永久代,之所以被稱爲永久代是相對於gc而言(原因應該是由於方法區中的一些信息從程序運行到結束一直存在,因此這個所謂的“永久”也是相對於程序運行而言),但實際上永久代與方法區並不等價,自Java7開始“去永久代”(永久代的存在容易導致內存泄露),可以說方法區是Java堆的一個邏輯區域(但實際上方法區並不屬於Java堆),該區域由所有線程共享。

    (五)、常量池:顧名思義,是用於存放常量的;該區域一開始在方法區當中,之後就放進了Java堆當中進行使用。

    (六)、直接內存:本身並不屬於虛擬機內存,但在一些程序運行時也會用到,主要是用於存放緩衝流緩衝區的數據,避免從Java堆與native堆中來回cp數據從而顯著提高運行效率。

二、對象的創建:

    (一)、首先會在棧中創建對象的引用。

    (二)、其次會在堆中查找是否有該對象所對應的數據,如果沒有則創建,在堆中創建對象的數據有兩種方式,至於是哪種主要取決於堆中的數據是否規整;如果規整,則用指針將已使用區與空閒區分隔開來,當創建對象數據時指針就會向空閒區移動爲數據騰出空間,因此這種方法也被稱之爲“指針碰撞”;如果不規整,虛擬機會維護出一個列表,列表中記錄了哪些區域是已用的哪些是空閒的,當創建對象數據時就會劃分出足夠大的空間用於存放數據,因此這種方法也被稱之爲“空閒列表”。

    (三)、最後,要通過對象的引用來使用對象數據就需要把它們關聯起來,主要的方法有使用句柄與直接指針兩種;如果是使用句柄,就會在Java堆中創建一個句柄池,句柄池中包含了對象數據和數據類型的地址,具體如圖所示(圖片來自《深入理解Java虛擬機》):

如果使用的是直接指針,那麼就是在對象的引用中存放了對象數據的具體地址,具體如下圖所示(圖片來自《深入理解Java虛擬機》):

兩種方法的優劣比較:使用句柄的好處是當對象的數據改變時,不需要直接移動引用的指針,只要移動句柄池指向對象數據的指針即可,而直接指針則需要直接移動引用指向對象數據的指針,但相比之下卻少了根指針的指向,因此對象的創建的速度會比較快;Java主要的虛擬機hotspot使用的便是直接指針。

三、內存溢出

    (一)、棧內存溢出:該內存溢出可以分爲兩種情況,一種是單個線程請求棧空間過大,從而拋出StackOverFlowerErr;另一種是棧內存擴容時申請的內存得不到滿足從而拋出OutOfMemoryError,而之所以會出現這種狀況是由於多線程運行下,線程本身佔用了大量的內存導致的,因此該內存溢出並不是棧內存過小導致的,恰恰相反,棧內存越大,多線程運行下拋出該異常的可能性也就越大;但從另外一個角度看,這兩種情況在本質上其實可以說是同一種情況的兩種說法,單線程向棧空間申請內存,棧空間本身不能滿足,於是進行擴容;當然,這是在沒有設置棧大小的前提下。

    (二)、除了程序計數器以爲,其它所有的內存空間都有可能出現內存溢出,從而拋出OOM異常。

發佈了49 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章