深入理解java虛擬機 摘要
目錄:
一、自動內(nèi)存管理機制
一、自動內(nèi)存管理機制
3. 實戰(zhàn):OutOfMemoryError異常
-
Java堆溢出:
測試代碼:
public class Tests { static class Obj{ } public static void main(String[] args) throws >Exception { List<Obj> list = new ArrayList<>(); while (true){ list.add(new Obj()); } } }
啟動參數(shù):
-Xmx20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
將堆的最小值-Xms參數(shù)與最大值-Xmx參數(shù)設(shè)置為一樣即可避免堆自動擴展潦蝇,通過參數(shù)-XX:+HeapDumpOnOutOfMemoryError可以讓虛擬機在出現(xiàn)內(nèi)存溢
出異常時Dump出當(dāng)前的內(nèi)存堆轉(zhuǎn)儲快照以便事后進行分析要解決這個區(qū)域的異常而柑,一般的手段是先通過內(nèi)存映像分析工具
ideal可使用JProfiler和JMeter插件進行分析 -
虛擬機棧和本地方法棧溢出
測試代碼:
public static class JavaVMStackSOF { private int stackLength = 1; public void stackLeak() { stackLength++; stackLeak(); } } public static void main(String[]args)throws Throwable{ JavaVMStackSOF oom=new JavaVMStackSOF(); try{ oom.stackLeak(); }catch(Throwable e){ System.out.println("stack length:"+oom.stackLength); throw e; } }
啟動參數(shù):
-Xss20m
對于HotSpot來說节芥,雖然-Xoss參數(shù)(設(shè)置本地方法棧大小)存在恐锦,但實際上是無效的滑燃,棧容量只由-Xss參數(shù)設(shè)定
如果線程請求的棧深度大于虛擬機所允許的最大深度曲横,將拋出StackOverflowError異常。如果虛擬機在擴展棧時無法申請到足夠的內(nèi)存空間不瓶,則拋出OutOfMemoryError異常。
這里把異常分成兩種情況灾杰,看似更加嚴(yán)謹(jǐn)蚊丐,但卻存在著一些互相重疊的地方:當(dāng)棧空間無法繼續(xù)分配時艳吠,到底是內(nèi)存太小麦备,還是已使用的棧空間太大,其本質(zhì)上只是對同一件事情的兩種描述而已凛篙。
在單個線程下黍匾,無論是由于棧幀太大還是虛擬機棧容量太小,當(dāng)內(nèi)存無法分配的時候呛梆,虛擬機拋出的都是StackOverflowError異常锐涯。
-
本機直接內(nèi)存溢出
DirectMemory容量可通過-XX:MaxDirectMemorySize指定,如果不指定填物,則默認與Java堆最大值(-Xmx指定)一樣
測試代碼:
public class Tests { private static final Long MB=1024L*1024L; public static void main(String[]args)throws Exception{ Field unsafeField=Unsafe.class.getDeclaredFields()[0]; unsafeField.setAccessible(true); Unsafe unsafe=(Unsafe)unsafeField.get(null); while(true){ unsafe.allocateMemory(MB); } } }
啟動參數(shù):
-Xss20m
代碼解釋:
越過了DirectByteBuffer類纹腌,直接通過反射獲取Unsafe實例進行內(nèi)存分配(Unsafe類的getUnsafe()方法限制了只有引導(dǎo)類加載器才會返回實例,也就是設(shè)計者希望只有rt.jar中的類才能使用Unsafe的功能)滞磺。因為升薯,雖然使用DirectByteBuffer分配內(nèi)存也會拋出內(nèi)存溢出異常,但它拋出異常時并沒有真正向操作系統(tǒng)申請分配內(nèi)存击困,而是通過計算得知內(nèi)存無法分配涎劈,于是手動拋出異常,真正申請分配內(nèi)存的方法是unsafe.allocateMemory()阅茶。由DirectMemory導(dǎo)致的內(nèi)存溢出趟妥,一個明顯的特征是在Heap Dump文件中不會看見明顯的異常,如果讀者發(fā)現(xiàn)OOM之后Dump文件很小坞生,而程序中又直接或間接使用了NIO英遭,那就可以考慮檢查一下是不是這方面的原因。