咱們能夠帶着如下幾個問題去學習自動內存管理機制,羅列以下: java
本文章主要總結問題一、問題2和問題3 算法
Java虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域,以下圖所示 數組
其中虛擬機棧、本地方法棧和程序技術器是線程私有的,方法區和堆是線程共享的. ide
做用:當前線程所執行的字節碼的行號指示器 學習
棧的做用:棧用於存儲局部變量表、操做數棧、動態連接和方法出口等信息. spa
其中局部變量表用於存放8種基本數據類型(boolean,byte,char,short,int,float,long,double)和reference類型. .net
reference類型: 線程
指向對象起始地址的引用指針 指針
指向一個表明對象的句柄 調試
指向一條字節碼指令的地址
可拋出兩種異常情況
線程請求的棧深度大於虛擬機所容許的棧深度,拋出StackOverflowError異常
當擴展時沒法申請到足夠的內存時會拋出OutOfMemoryError異常
與虛擬機棧的做用很是類似.其區別是虛擬機棧執行Java方法服務,而本地方法棧則爲虛擬機使用到的Native方法服務
同時也會拋出StackOverflowError和OutOfMemoryError異常
堆的做用:分配全部的對象實例和數組。能夠拋出OutOfMemoryError異常。
方法區的做用:用於存儲已被虛擬機加載的類信息(Class)、常量(final修飾)、靜態變量(static)和即時編譯器編譯後的代碼(code)
能夠拋出OutOfMemoryError異常
屬於方法區的一部分,用於存放編譯期生成的各類字面量和符號引用(在之後介紹Class結構會講到),在類加載後存放到方法區的運行時常量池中。可拋出OutOfMemoryError異常
主流的兩種訪問方式:使用句柄和直接指針。(HotSpot虛擬機就是使用直接指針的訪問方式)
使用句柄訪問
使用直接指針訪問
優缺點比較
在Java虛擬機規範的描述中,除了程序計數器外,虛擬機內存的其餘幾個運行時區域都有發生OutOfMemoryError異常的可能.
下面經過若干實例來驗證異常發生的場景.如下代碼的開頭都註釋了執行時所須要設置的虛擬機啓動參數,這些參數對實驗結果有直接影響,請調試代碼的時候不要忽略掉.
堆裏放的是new出來的對象,因此這部分很簡單不斷的new對象就能夠了,可是爲了防止對象new出來以後被GC,因此把對象new出來的對象放到一個List中去便可。爲了有更好的效果,能夠在運行前,調整堆的參數。
import java.util.ArrayList; import java.util.List; /** * VM Args: -Xms20m -Xms20m - XX:+HeapDumpOnOutOfMemoryError * @author Administrator * */ public class HeapOOM { static class OOMObject{} public static void main(String[] args) { List<OOMObject> list = new ArrayList<HeapOOM.OOMObject>(); while(true ){ list.add( new OOMObject()); } } }
運行結果
/** * VM Args: - Xss64k * @author Administrator * */ public 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; } } }
import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodProxy; /** * VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m * @author Administrator * */ public class JavaMethodAreaOOM { public static void main(String[] args) { while (true ){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOMObject. class ); enhancer.setUseCache( false ); enhancer.setCallback( new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invoke(obj, args); } }); enhancer.create(); } } static class OOMObject{ } }
import java.util.ArrayList; import java.util.List; /** * VM Args:- XX:PermSize=10m -XX:MaxPermSize=10m * @author Administrator * */ public class RuntimeConstantPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<String>(); int i = 0; while (true ){ list.add(String. valueOf(i++).intern()); } } }
主要介紹虛擬機裏面的內存是如何劃分的,哪部分區域、什麼樣的代碼和操做可能致使內存溢出異常。
---------------------------------全文完------------------------------