1. 程式人生 > >Java虛擬機系列(三)---內存溢出情況及解決方法

Java虛擬機系列(三)---內存溢出情況及解決方法

方法 運行時常量池溢出 超過 stack 必須 解決 字節 maxperm 描述

因為Java虛擬機內存有堆內存、方法區、虛擬機棧、本地方法棧和程序計數器五部分組成,其中程序計數器是唯一一塊不會發生內存溢出異常的內存區,所以只有四類內存區可能發生內存溢出異常,其中虛擬機棧和本地方法棧都是Java方法執行的內存模型,所以它們的異常發生情況幾乎相同,另外,在方法區中。又有一塊內存是常量池,所以內存溢出的情況可分為Java堆溢出、虛擬機棧和本地方法棧溢出、方法區和運行時常量池溢三種情況。

一、Java堆溢出

1、產生的原因:因為堆中存放的是對象實例和數組,所以當對象數量>最大堆容量限制時,就會發生內存溢出異常;

2、解決方案:

1)如果對象不是必須的,但是又有指向GC Root(後面章節介紹)的引用鏈,此時無法被GC,就會出現內存泄露,可通過定位泄露原因在代碼中找到解決方案;

2)如果對象是必須的,就要檢查虛擬機棧的堆參數能否調大(當虛擬機內存總容量小於物理內存時可以調大),如果能調大可通過修改該參數來解決:

--Xmx:最大堆內存

--Xms:最小堆內存

如果--Xmx和--Xms相同,則說明堆內存不可動態擴展。

二、虛擬機棧和本地方法棧溢出

1、發生內存溢出的原因:

由於在HotSpot虛擬機中,不區分虛擬機棧和本地方法棧,所以設置本地方法棧大小的參數--Xoss無效,一般通過--Xss參數設置棧容量(我猜測ss是stack size的縮寫,這樣比較好記)

虛擬機中定義了兩種異常情況:

1)當線程申請的棧深度超過虛擬機允許的最大棧深度時,會發生StackOverflowError異常;

2)當棧內存擴展時,如果不能申請到足夠的內存,就會發生OutOfMemoryError異常

我們知道這部分內存是線程私有的,每個線程都需要分配一塊內存,所以當線程很多時就會發生內存溢出,下面來分析一下這句話背後的原理:

①內存容量=堆內存+方法區內存+程序計數器內存(可忽略)+棧內存(虛擬機棧和本地方法棧);

②因為棧容量在編譯器就可知,且一旦分配在運行期就不會改變,在棧容量一定的情況下,每個虛擬機棧分配到的棧容量越大,可以創建的線程數就越少;

③當線程過多時,就會導致棧容量不足,從而發生內存溢出;

2、解決方法:

首先,判斷能不能減少線程數,如果能則減少線程數;如果不能減少線程數,就只能

通過減小最大堆內存容量和最大棧容量來解決:

1)--Xmx:減少

2)--Xss:減少

三、方法區和運行時常量池溢出

1、異常發生原因

方法區主要存儲class的相關信息,如類,名、訪問修飾符、常量池、字段描述信息、方法描述信息等,所以如果運行時產生大量的類去填滿方法區,就能出現內存溢出異常。這裏就涉及到如何動態產生大量類的方法,一般有如下兩種:

1)使用反射機制或動態代理

2)使用CGLib直接操作字節碼

2、解決方法:

通過調節方法區大小參數--XX:PermSize和-XX:MaxPermSize限制方法區大小,當設置成相同的值時不可擴展。

除以上三種虛擬機內存溢出情況之外,還有一種本機直接內存溢出,可通過調節參數-XX:MaxDirectMemorysize指定,若不指定,則和Java堆內存大小一樣。

以上就是Java虛擬機中的幾種內存溢出情況及解決方法。

Java虛擬機系列(三)---內存溢出情況及解決方法