一、虛擬機的發展
HotSpot VM(SUN) 以前使用範圍最廣的Java虛擬機
JRockit VM(BEA) 號稱”世界上最快的Java虛擬機”
J9 VM(IBM)
Dalvik VM( Google )
HotSpot VM(ORACLE) 目前使用範圍最廣的Java虛擬機
二、JVM的整體介紹
三、運行時數據區
四、程序計數器
五、棧
棧(Stack):數據結構 入口和出口只有一個 入棧 出棧
特點 先進後出(FIL0)
異常:
線程請求的棧深度大於虛擬機所允許的深度:StackOverflowError
JVM動態擴展時無法申請到足夠的內存時:OutOfMemoryError
六、虛擬機棧
七、本地方法棧
八、線程共享區域
方法區(永久代(JDK1.7和以前)、元空間(JDK1.8)) 類信息 常量 靜態變量 即時編譯期編譯後的代碼
Java堆(-Xms;-Xmx;-Xmn) 堆是需要重點關注的一塊區域,因爲涉及到內存的分配(new關鍵字,反射等)與回收(回收算法,收集器等) 幾乎所有的對象都是在堆中分配.
九、JVM各版本內存區域的變化
運行時常量池 Class 文件中的常量池(編譯器生成的各種字面量和符號引用)會在類加載後被放入這個區域。
JDK1.6 運行時常量池在方法區中
JDK1.7 運行時常量池在堆中
JDK1.8 去永久代:使用元空間(空間大小隻受制於機器的內存)替代永久代
永久代參數
-XX:PermSize;-XX:MaxPermSize =100M 超過100M OOM()
元空間參數
-XX:MetaspaceSize; -XX:MaxMetaspaceSize
爲什麼會這樣呢?
永久代來存儲類信息、常量、靜態變量等數據不是個好主意, 很容易遇到內存溢出的問題。 對永久代進行調優是很困難的,同時將元空間與堆的垃圾回收進行了隔離,避免永久代引發的Full GC和OOM等問題;
十、直接內存
不是虛擬機運行時數據區的一部分,也不是java虛擬機規範中定義的內存區域;
如果使用了NIO,這塊區域會被頻繁使用,在java堆內可以用directByteBuffer對象直接引用並操作;
這塊內存不受java堆大小限制,但受本機總內存的限制,可以通過MaxDirectMemorySize來設置(默認與堆內存最大值一樣),所以也會出現OOM異常;
避免了在Java 堆和Native 堆中來回複製數據,能夠提高效率
十一、站在線程角度看JVM
十二、深入分析堆和棧
功能
以棧幀的方式存儲方法調用的過程,並存儲方法調用過程中基本數據類型的變量(int、short、long、byte、float、double、boolean、char等)以及對象的引用變量,其內存分配在棧上,變量出了作用域就會自動釋放;(stackoverflow,OOM)
而堆內存用來存儲Java中的對象。無論是成員變量,局部變量,還是類變量,它們指向的對象都存儲在堆內存中;
線程獨享還是共享
棧內存歸屬於單個線程,每個線程都會有一個棧內存,其存儲的變量只能在其所屬線程中可見,即棧內存可以理解成線程的私有內存。
堆內存中的對象對所有線程可見。堆內存中的對象可以被所有線程訪問。
空間大小
棧的內存要遠遠小於堆內存,棧的深度是有限制的,可能發生StackOverFlowError問題。
十三、JVM中對象的分配
十四、對象的內存佈局
十五、對象的訪問方式
句柄是一種特殊的智能指針 。句柄與普通指針的區別在於,指針包含的是引用對象的內存地址,而句柄則是由系統所管理的引用標識,該標識可以被系統重新定位到一個內存地址上。
十六、堆內存分配策略
堆進一步劃分 新生代(PSYoungGen) Eden空間 From Survivor空間 To Survivor空間 老年代(ParOldGen)
堆中參數配置:
新生代大小: -Xmn20m 表示新生代大小20m(初始和最大)
-XX:SurvivorRatio=8 表示Eden和Survivor的比值, 缺省爲8 表示 Eden:From:To= 8:1:1 2 Eden:From:To= 2:1:1
對象優先在Eden分配 大對象直接進入老年代 長期存活的對象將進入老年代 動態對象年齡判定 空間分配擔保
後續會持續更新JVM算法!!!