深入理解Java虚拟机(JVM高级特性与最佳实践java虚拟机)的一些知识总结
GC在什么時候對什么做了什么?
??????? 要回答這個問題,先了解下GC的發展史、jvm運行時數據區的劃分、jvm內存分配策略、jvm垃圾收集算法等知識。
??????? 先說下jvm運行時數據的劃分,粗暴的分可以分為堆區(Heap)和棧區(Stack),但jvm的分法實際上比這復雜得多,大概分為下面幾塊:
??????? 1、程序計數器(Program Conuter Register)
??????? 程序計數器是一塊較小的內存空間,它是當前線程執行字節碼的行號指示器,字節碼解釋工作器就是通過改變這個計數器的值來選取下一條需要執行的指令。它是線程私有的內存,也是唯一一個沒有OOM異常的區域。
??????? 2、Java虛擬機棧區(Java Virtual Machine Stacks)
??????? 也就是通常所說的棧區,它描述的是Java方法執行的內存模型,每個方法被執行的時候都創建一個棧幀(Stack Frame),用于存儲局部變量表、操作數棧、動態鏈接、方法出口等。每個方法被調用到完成,相當于一個棧幀在虛擬機棧中從入棧到出棧的過程。此區域也是線程私有的內存,可能拋出兩種異常:如果線程請求的棧深度大于虛擬機允許的深度將拋出StackOverflowError;如果虛擬機??梢詣討B的擴展,擴展到無法動態的申請到足夠的內存時會拋出OOM異常。
??????? 3、本地方法棧(Native Method Stacks)
??????? 本地方法棧與虛擬機棧發揮的作用非常相似,區別就是虛擬機棧為虛擬機執行Java方法,本地方法棧則是為虛擬機使用到的Native方法服務。
??????? 4、堆區(Heap)
??????? 所有對象實例和數組都在堆區上分配,堆區是GC主要管理的區域。堆區還可以細分為新生代、老年代,新生代還分為一個Eden區和兩個Survivor區。此塊內存為所有線程共享區域,當堆中沒有足夠內存完成實例分配時會拋出OOM異常。
??????? 5、方法區(Method Area)
?????? 方法區也是所有線程共享區,用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯后的代碼等數據。GC在這個區域很少出現,這個區域內存回收的目標主要是對常量池的回收和類型的卸載,回收的內存比較少,所以也有稱這個區域為永久代(Permanent Generation)的。當方法區無法滿足內存分配時拋出OOM異常。
??????? 6、運行時常量池(Runtime Constant Pool)
??????? 運行時常量池是方法區的一部分,用于存放編譯期生成的各種字面量和符號引用。
?
??????? 垃圾收集(Garbage Collection)并不是Java獨有的,最早是出現在Lisp語言中,它做的事就是自動管理內存,也就是下面三個問題:
1、什么時候回收
2、哪些內存需要回收
3、如何回收
?
?1、什么時候回收?
???????? 上面說到GC經常發生的區域是堆區,堆區還可以細分為新生代、老年代,新生代還分為一個Eden區和兩個Survivor區。
??????? 1.1?對象優先在Eden中分配,當Eden中沒有足夠空間時,虛擬機將發生一次Minor GC,因為Java大多數對象都是朝生夕滅,所以Minor GC非常頻繁,而且速度也很快;
??????? 1.2?Full GC,發生在老年代的GC,當老年代沒有足夠的空間時即發生Full GC,發生Full GC一般都會有一次Minor GC。大對象直接進入老年代,如很長的字符串數組,虛擬機提供一個-XX:PretenureSizeThreadhold參數,令大于這個參數值的對象直接在老年代中分配,避免在Eden區和兩個Survivor區發生大量的內存拷貝;
??????? 1.3?發生Minor GC時,虛擬機會檢測之前每次晉升到老年代的平均大小是否大于老年代的剩余空間大小,如果大于,則進行一次Full GC,如果小于,則查看HandlePromotionFailure設置是否允許擔保失敗,如果允許,那只會進行一次Minor GC,如果不允許,則改為進行一次Full GC。
?
?2、哪些內存需要回收
??????? jvm對不可用的對象進行回收,哪些對象是可用的,哪些是不可用的?Java并不是采用引用計數算法來判定對象是否可用,而是采用根搜索算法(GC Root Tracing),當一個對象到GC Roots沒有任何引用相連接,用圖論的來說就是從GC Roots到這個對象不可達,則證明此對象是不可用的,說明此對象可以被GC。對于這些不可達對象,也不是一下子就被GC,而是至少要經歷兩次標記過程:如果對象在進行根搜索算法后發現沒有與GC Roots相連接的引用鏈,那它將會第一次標記并且進行一次篩選,篩選條件是此對象有沒有必要執行finalize()方法,當對象沒有覆蓋finalize()方法或者finalize()方法已經被虛擬機調用執行過一次,這兩種情況都被視為沒有必要執行finalize()方法,對于沒有必要執行finalize()方法的將會被GC,對于有必要有必要執行的,對象在finalize()方法中可能會自救,也就是重新與引用鏈上的任何一個對象建立關聯即可。
?
?3、如何回收
??????? 選擇不同的垃圾收集器,所使用的收集算法也不同。
在新生代中,每次垃圾收集都發現有大批對象死去,只有少量存活,則使用復制算法,新生代內存被分為一個較大的Eden區和兩個較小的Survivor區,每次只使用Eden區和一個Survivor區,當回收時將Eden區和Survivor還存活著的對象一次性的拷貝到另一個Survivor區上,最后清理掉Eden區和剛才使用過的Survivor區,Eden和Survivor的默認比例是8:1,可以使用-XX:SurvivorRatio來設置該比例。
?????? 而老年代中對象存活率高,沒有額外的空間對它進行分配擔保,必須使用“標記-清理”或“標記-整理”算法。
?
總結
以上是生活随笔為你收集整理的深入理解Java虚拟机(JVM高级特性与最佳实践java虚拟机)的一些知识总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (转) Android生成签名文件并用其
- 下一篇: oracle 条件查询,比较运算符,逻辑