Java 內存區域與內存溢出異常

一.運行時數據區域

1 . 程序計數器(Program Counter Register):

是一塊較小內存空間,它可看作是當前線程所執行的字節碼的行號指示器。各線程都會享有自己獨立的程序計數器,這樣保證線程之前計數據器互不影響,所以這類內存區域爲“線程私有”的內存。

2 . java虛擬機棧(Java Virtual Machine Stacks)

也是線程私有的,它的生命同期與線程相同,它描述的是Java方法執行的內存模型:每個方法在運行的時候會創建一個棧楨用於存儲局部變量表、操作數棧、動態鏈接、方法出口等。在該內存區域有兩種異常情況:StackOverflowError,當線程請求的棧深度超出虛擬機所允許的深度地拋出該異常;OutOfMemoryError,若虛擬機棧可動態擴展的,而當擴展時無法申請到足夠的內存就會拋出該異常。

3 .本地方法棧

與虛擬機棧很相似,區別是虛擬機棧爲虛擬機執行Java方法服務,本地方法棧則爲虛擬機執行Native方法服務

4 .Java 堆

Java堆是虛擬機管理的內存中最大的一塊,是被所有線程共享的一塊內存區域,在虛擬機啓動地創建,此內存區域唯一目的就是存放對象實例。Java堆是垃圾收集順管理的主要區域,因此也被稱做”GC堆“。由於現在收集器基本都採用分代碼收集算法,所以Java堆又可細分爲:新生代和老年代,再細緻一點又有:Eden空間、FormSurvivor空間、To Survivor空間。如此劃分的目的是爲了更好的回收內存,或者更快的分配內存。

5 .方法區

方法區與Java堆一樣是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。它有一個別名叫Non-Heap(非堆),目的大概是與Java堆區分開來。在HotSpot虛擬機上又被稱爲”永久代“。而我經常使用的虛擬機就是HotSpot,永久大小可通過下面參數進行配製:
-XX:PermSize來指定初始化是永久代大小和
-XX:MaxPermSize來指定永久代最大內存。
當方法區無法滿足內存靈機一動需求時,將拋出OutOfMemoryError異常。

6 .運行時常量池

運行時常量池是方法區的一部分。Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池,用於存放 編譯期生成的各種字面量和符號 引用,這部分內容將在類加載後進入方法區的運行時常量池中存放。一般來說,除了保存Class文件中描述的符號引用外,還會把翻譯出來的直接引用也存儲在運行時常量池中。

7 .直接內存

在JDK1.4中新加入NIO(New Input/Output)類,引入了一種基於通道與緩衝區(Buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,然後通過 一個存儲在Java堆中的DirectByteBuffer對象作爲這塊內存的引用進行操作。這樣能在一些場景中提高性能,因爲避免了在Java堆和Native堆中來回複製數據。

二對象創建

1、遇到new指令時,首先在常量池中尋找該在的符號引用,並且檢查這個符號引用代表 類是否加載、解析和初始經過,如果沒有,那執行相應加載過程。
2、虛擬機爲新生對象分配內存。所需內存大小在類加載完成後即可完全確定。虛擬機需從堆中劃分相同大小的內存空間。劃分方式:指針碰撞和空閒列表,使用哪種方式是由所採用的器是否帶有壓縮整理功能決定。由於對象創建非常頻繁的,在併發情況下並不是線程安全的。解決這個問題有兩種方案:一種,對分配內存空間的動作進行同步處理;另一種按線程劃分在不同空間中進行,即每個線程在Java堆中預先分配一小塊內存,稱爲本地線程分配緩衝TLAB。虛擬機是否使用TLAB,可通過:
-XX:+/-UseTLAB參數來設定。
3、將分配到的內存空間都初始化爲零值,這步操作就是Java對象屬性默認值的來源;
4、設置對象頭,如對象是哪個類的實例、如何才能找到類的元數據信息、對象的哈希碼、GC分代年齡等信息。

三、內存泄漏與內存溢出

1 .內存泄漏

是指,爲對象分配了內存空間後,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積後果很嚴重,無論多少內存,遲早會被佔光。memory leak會最終會導致out of memory!

2 .內存溢出

是指,爲對象申請內容空間時,無法申請到足夠空間而拋出OutOfMemoryError。

3 .隱式泄漏

是指,一個線程或方法長時間運行在虛擬機中,導致與該線程相關的內存區域不能及時釋放,但當線程或方法一旦運行完成,與線程相關的內在區域即可釋放。

總結:從用戶使用程序的角度來看,內存泄漏本身不會產生什麼危害,作爲一般的用戶,根本感覺不到內存泄漏的存在。真正有危害的是內存泄漏的堆積,這會最終消耗盡系統所有的內存。從這個角度來說,一次性內存泄漏並沒有什麼危害,因爲它不會堆積,而隱式內存泄漏危害性則非常大,因爲較之於常發性和偶發性內存泄漏它更難被檢測到

四、JVM常用參數

-Xms40m  #指虛擬機啓動時即創建40M的堆空間
-Xmx512m #指堆了大值爲512M
-XX:MaxPermsize=256m  #指永久代最大值爲256M。 
-Xverify:none #禁止字節碼驗證過程
-XX:+DisableExplicitGC  #屏蔽System.gc()操作。
-Xoss40m #設置本地方法棧大小,這裏亂寫的。
-Xss1024k  #設置棧容量
-XX:HeapDumpOnOutOfMemoryError  #讓虛擬機在出現內存逆風異常地Dump出當前的內存堆轉存儲快照。
-XX:PretenureSizeThreshold=2m #申請對象大於2M時直接進入老年代
-XX:+DisableExplicitGC ##禁用系統中的System.gc()
-XX:+BackgroundCompilation #啓用JIT編譯優化
-Xloggc:/home/xieyu/logs/gc.log  #將常量GC日誌輸出到文件
-XX:CMSInitiatingOccupancyFraction=70  ##當老年代使用率達70%之後啓動CMS GC

垃圾收集器選擇

-XX:+UseConcMarkSweepGC
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章