摘要:主要在堆上分配內存,而堆又分為新生代和老年代兩個部分,新生代又再分為區和區兩部分,本文根據堆的劃分,描述的內存分配策略。
java主要在堆上分配內存,而Java堆又分為新生代(YoungGen)和老年代(OldGen)兩個部分,新生代又再分為Eden區和Survivor區兩部分,本文根據java堆的劃分,描述hotspot的內存分配策略。
GC垃圾收集分類Minor GC: 發生在新生代中的垃圾收集,采用復制算法。
Major GC/Full GC: 發生在老年代的垃圾收集動作,所采用的是標記-清除或者標記-整理算法。
Eden區和Survivor區對于采用復制算法的虛擬機,新生代通常有一個Eden區和兩個Survivor區。
對象優先在Eden區分配,當Eden區沒有足夠的空間進行分配時,虛擬機講發起一次Minor GC,Eden中存活的對象將被移動到第一塊Survivor區S1,Eden被清空。
當Eden區再次填滿,再次觸發Minor GC,Eden區和S1中的存活對象被復制送入第二塊Survivor區S2中,S1和Eden被清空,下一輪交換S1和S2的角色。
使用兩個Survivor區能夠簡化復制算法的過程,并且避免復制過程中內存碎片的產生。
當對象的復制次數達到-XX:MaxTenuringThreshold設置的值(默認-XX:MaxTenuringThreshold=15)時,將被移至老年代。
實驗/** * VM Options: * -Xmx20M 堆最大20M * -Xms20M 堆最小20M * -Xmn10M 新生代為10M * -XX:SurvivorRatio=8 Eden區和Survivor區的比值為8:1 * -XX:+PrintGCDetails 輸出回收日志及退出時內存各區域情況 */ private static final int _1MB = 1024 * 1024; public static void testAllocation(){ byte[] allocation1,allocation2,allocation3,allocation4; allocation1 = new byte[2 * _1MB]; allocation2 = new byte[2 * _1MB]; allocation3 = new byte[2 * _1MB]; allocation4 = new byte[4 * _1MB]; }
結果:
PSYoungGen total 9216K, used 7479K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000) eden space 8192K, 91% used [0x00000007bf600000,0x00000007bfd4df10,0x00000007bfe00000) from space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000) to space 1024K, 0% used [0x00000007bfe00000,0x00000007bfe00000,0x00000007bff00000) ParOldGen total 10240K, used 4096K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000) object space 10240K, 40% used [0x00000007bec00000,0x00000007bf000010,0x00000007bf600000) Metaspace used 2692K, capacity 4486K, committed 4864K, reserved 1056768K class space used 288K, capacity 386K, committed 512K, reserved 1048576K
在退出時各個區域結果如上, PSYoungGen的PS指的是Parallel Scavenge垃圾回收器,ParOldGen中的Par指的是Parallel Old垃圾回收器。
設置中堆為10M,新生代為10M,因此老年代為10M。設置SurvivorRatio為8:1,因此Eden區大小為8M,Survivor區大小為1M。因為Survivor區同一時刻只有一個能用于分配,因此PSYoungGen區域總可用大小為9M。
在allocation4進行分配時,新生代eden區已經用了6M,只剩2M,無法進行分配,觸發MinorGC。新生代中3個2M大小的對象全部無法放入1M的Survivor區中,所以只能通過分配擔保機制將兩個2M的對象放入老年代中,再將allocation4的4M對象放入Eden區中。
最終Eden區分配6M,survivor區中沒有對象,老年代分配4M。
大對象是指需要大量連續內存空間的Java對象。為了避免在Eden區及兩個Survivor區之間發生大量的內存復制,虛擬機提供了-XX:PretenureSizeThreshold參數。大于該參數設置值的對象將直接分配在老年代。
長期存活對象直接進入老年代虛擬機給每個對象定義了一個對象年齡計數器,對象每經過一個MinorGC仍然存活,則年齡加一,當年齡增加到超過-XX:MaxTenuringThreshold設置的值(默認為16)時,將被移至老年代。
空間分配擔保如文章開頭的例子中,當出現大量對象在MinorGC后仍然存活的情況,Survivor區無法容納多余的對象,此時,需要老年代進行分配擔保,把Survivor無法容納的對象直接進入老年代。JDk 6 Update 24之后,擔保的規則是,只要老年代的連續空間大于新生代對象總大小或者歷次晉升的平均大小就會進行MinorGC,否則將進行Full GC。
參數設置小結參數 | 描述 |
---|---|
-Xms20M | 堆最小值 |
-Xmx20M | 堆最大值 |
-Xmn10M | 新生代大小 |
-XX:SurvivorRatio=8 | Eden區比Survivor區的大小 |
-XX:+PrintGCDetails | 輸出回收日志和退出時各內存區域情況 |
-XX:PretenureSizeThreshold=10M | 大于該參數設置值的對象直接分配在老年代 |
-XX:MaxTenuringThreshold=15 | 新生代對象年齡增加到超過該值時,將被移至老年代 |
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69445.html
摘要:概要要理解的內存管理策略,首先就要熟悉的運行時數據區,如上圖所示,在執行程序的時候,虛擬機會把它所管理的內存劃分為多個不同的數據區,稱為運行時數據區。 這是一篇有關JVM內存管理的文章。這里將會簡單的分析一下Java如何使用從物理內存上申請下來的內存,以及如何來劃分它們,后面還會介紹JVM的核心技術:如何分配和回收內存。 JMM ( Java Memory Model )概要 show...
摘要:目錄往期博客課堂篇初識常量池簡單理解字符串常量池靜態常量池大整型常量池為什么要了解垃圾收集和內存分配如何判斷對象已死引用計數算法可達性分析算法之后引用的擴充回收方法區垃圾收集算法分代收集理論標記清除標記復制標記整理對象分 ...
摘要:騰訊特約作者姚潮生首先以一個內存泄露實例來開始本節基礎概念的內容。堆內存用于存放所有由創建的對象內容包括該對象其中的所有成員變量和數組。回到我們的問題,為什么內存會泄露堆內存中的長生命周期的對象持有短生命周期對象的強軟引用,盡管 騰訊Bugly特約作者: 姚潮生 首先以一個內存泄露實例來開始本節基礎概念的內容。 實例1:單例導致內存對象無法釋放而泄露 showImg(http://i....
摘要:虛擬機所處的區域,則表示它是屬于新生代收集器還是老年代收集器。虛擬機總共運行了分鐘,其中垃圾收集花掉分鐘,那么吞吐量就是。收集器線程所占用的數量為。 本文主要從GC(垃圾回收)的角度試著對jvm中的內存分配策略與相應的垃圾收集器做一個介紹。 注:還是老規矩,本著能畫圖就不BB原則,盡量將各知識點通過思維導圖或者其他模型圖的方式進行說明。文字僅記錄額外的思考與心得,以及其他特殊情況 內存...
摘要:內存泄漏總結內存管理的目的就是讓我們在開發中怎么有效的避免我們的應用出現內存泄漏的問題。在中,內存泄漏的范圍更大一些。 Android 內存泄漏總結 內存管理的目的就是讓我們在開發中怎么有效的避免我們的應用出現內存泄漏的問題。內存泄漏大家都不陌生了,簡單粗俗的講,就是該被釋放的對象沒有釋放,一直被某個或某些實例所持有卻不再被使用導致 GC 不能回收。最近自己閱讀了大量相關的文檔資料,打...
閱讀 1063·2021-11-12 10:34
閱讀 991·2021-09-30 09:56
閱讀 671·2019-08-30 15:54
閱讀 2607·2019-08-30 11:14
閱讀 1470·2019-08-29 16:44
閱讀 3210·2019-08-29 16:35
閱讀 2496·2019-08-29 16:22
閱讀 2446·2019-08-29 15:39