搜尋
首頁Javajava教程淺談java記憶體分配與回收策略

淺談java記憶體分配與回收策略

Jun 26, 2017 am 10:41 AM
java記憶體分配回收

一、導論

  java技術體系中所提到的記憶體自動化管理歸根究底就是記憶體的分配與回收兩個問題,之前已經和大家談過java回收的相關知識,今天來和大家聊聊java物件的在記憶體中的分配。通俗的講,物件的記憶分配就是在堆上的分配,物件主要分配在新生代的Eden上(關於物件在記憶體上的分代在垃圾回收中會補上,想了解的也可以參考《深入理解java虛擬機器》),如果啟動了本地執行緒分配緩衝,講按執行緒優先在TLAB上分配。少數情況下也是直接在老年代中分配。

二、經典的分配策略

1、物件優先在Eden上分配

  一般情況下物件都是優先分配在Eden上,當Eden沒有足夠的空間進行分配時,jvm會發起一次Minor GC。如果還是沒有足夠的空間分配,後面還有另外的措施,下面會提到。

  設定虛擬機器的偶記日誌參數-XX:+PrintGCDetails,在垃圾回收的時候會列印記憶體的回收日誌,並且在進程退出的時候會輸出目前記憶體各區域的分配。下面來看下具體的例子,首先需要設定jvm的參數-Xms20m -Xmx20m -Xmn10m,這三個參數說明java堆大小為20M,且不可擴展,其中10M分配給新生代,剩下的10M分配給老年代。 -XX:SurvivorRatio=8是jvm預設的新生代中Eden和Survivor比例,預設為8:1。原因是新生代中的物件98%都會在下次GC的時候回收掉,所以很適合採用複製演算法進行垃圾回收,所以新生代10M的記憶體中,8M是Eden,1M是Survivor,另外的1M是未使用配合複製演算法的記憶體區塊,也是Survivor。

 1 public class ReflectTest { 2  3     private static final int _1MB = 1024*1024; 4      5     public static void testAllocation(){ 6         byte[] allocation1 , allocation2 , allocation3 , allocation4; 7         allocation1 = new byte[2 * _1MB]; 8         allocation2 = new byte[2 * _1MB]; 9         allocation3 = new byte[2 * _1MB];10         allocation4 = new byte[6 * _1MB];11     }12     13     public static void main(String[] args) {14         ReflectTest.testAllocation();15     }16     17 }

 輸出如下

Heap
 PSYoungGen      total 9216K, used 6651K [0x000000000b520000, 0x000000000bf20000, 0x000000000bf20000)
  eden space 8192K, 81% used [0x000000000b520000,0x000000000bb9ef28,0x000000000bd20000)
  from space 1024K, 0% used [0x000000000be20000,0x000000000be20000,0x000000000bf20000)
  to   space 1024K, 0% used [0x000000000bd20000,0x000000000bd20000,0x000000000be20000)
 PSOldGen        total 10240K, used 6144K [0x000000000ab20000, 0x000000000b520000, 0x000000000b520000)
  object space 10240K, 60% used [0x000000000ab20000,0x000000000b120018,0x000000000b520000)
 PSPermGen       total 21248K, used 2973K [0x0000000005720000, 0x0000000006be0000, 0x000000000ab20000)
  object space 21248K, 13% used [0x0000000005720000,0x0000000005a07498,0x0000000006be0000)

 可以看到eden佔用了81%,說明allocation1 , allocation2 , allocation3 都是分配在新生代Eden上。

2、大物件直接分配在老年代上

  大對像是指需要大量連續記憶體空間去存放的對象,類似於那種很長的字串和陣列。大物件對於虛擬機器的記憶體分佈來講並不是好事,當遇到很多存活僅一輪的大物件jvm更難處理,寫程式碼的時候應該避免這樣的問題。虛擬機器中提供了-XX:PretenureSizeThreshold參數,另大於這個值的物件直接分配到老年代,這樣做的目的是為了避免在Eden區和Survivor區之間發生大量的記憶體copy,在之前講過的垃圾回收演算法複製演算法有提到過,就不多說了。

public class ReflectTestBig {private static final int _1MB = 1024*1024;    public static void testAllocation(){byte[] allocation2 , allocation3 , allocation4;allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation4 = new byte[6 * _1MB];
    }    public static void main(String[] args) {
        ReflectTestBig.testAllocation();
    }
    
}

 輸出如下

Heap
 PSYoungGen      total 8960K, used 4597K [0x000000000b510000, 0x000000000bf10000, 0x000000000bf10000)
  eden space 7680K, 59% used [0x000000000b510000,0x000000000b98d458,0x000000000bc90000)
  from space 1280K, 0% used [0x000000000bdd0000,0x000000000bdd0000,0x000000000bf10000)
  to   space 1280K, 0% used [0x000000000bc90000,0x000000000bc90000,0x000000000bdd0000)
 PSOldGen        total 10240K, used 6144K [0x000000000ab10000, 0x000000000b510000, 0x000000000b510000)
  object space 10240K, 60% used [0x000000000ab10000,0x000000000b110018,0x000000000b510000)
 PSPermGen       total 21248K, used 2973K [0x0000000005710000, 0x0000000006bd0000, 0x000000000ab10000)
  object space 21248K, 13% used [0x0000000005710000,0x00000000059f7460,0x0000000006bd0000)

 可以看到allocation4已經超過了設定的-XX:PretenureSizeThreshold=3145728,隨意allocation4直接被分配到了老年代,老年代佔用率為60%。注意這裡設定-XX:PretenureSizeThreshold=3145728不能寫成-XX:PretenureSizeThreshold=3m,否則jvm將無法辨識。

3、長期存活的物件將進入老年代

  虛擬機既然採用了分帶收集的思想來管理內存,那麼內存回收就必須識別哪些對象應該放在新生代,哪些對象應該放在老年代。為了打到目的,jvm為每個物件定義了一個年齡計數器(Age)。如果物件在Eden出生並且能過第一次Minor GC後仍然存活,並且可以在Survivor存放的話,將被移動到Survivor中,並將對象的年齡設為1。對象每躲過一次Minor GC,年齡就會加1,當他的年齡超過一年的閾值的時候,該對象就會晉升到老年代。這個閾值jvm預設是15,可以透過-XX:MaxTenuringThreshold來設定。

   m = 1024 * 1024  [] a1 =  [1 * m / 4[] a2 =  [7 *[] a3 =  [3 * m];

 輸出如下

[GC [DefNew: 7767K->403K(9216K), 0.0062209 secs] 7767K->7571K(19456K), 0.0062482 secs]   
[Times: user=0.00 sys=0.00, real=0.01 secs]   
a3 ok  
Heap  
 def new generation   total 9216K, used 3639K [0x331d0000, 0x33bd0000, 0x33bd0000)  
  eden space 8192K,  39% used [0x331d0000, 0x334f9040, 0x339d0000)  
  from space 1024K,  39% used [0x33ad0000, 0x33b34de8, 0x33bd0000)  
  to   space 1024K,   0% used [0x339d0000, 0x339d0000, 0x33ad0000)  
 tenured generation   total 10240K, used 7168K [0x33bd0000, 0x345d0000, 0x345d0000)  
   the space 10240K,  70% used [0x33bd0000, 0x342d0010, 0x342d0200, 0x345d0000)  
 compacting perm gen  total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000)  
   the space 12288K,   3% used [0x345d0000, 0x3462f548, 0x3462f600, 0x351d0000)  
    ro space 10240K,  55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000)  
    rw space 12288K,  55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)
#

You can see that a2 has survived once, and its age is 1, which satisfies the set -XX:MaxTenuringThreshold=1, so a2 has entered the old generation, and a3 has entered the new generation.

4. Dynamic object age determination

In order to better adapt to the memory status of different programs, the virtual machine does not always require that the age of the object must reach the value set by -XX:MaxTenuringThreshold. In order to be promoted to the old age, if the sum of the sizes of all objects of the same age in the Survivor space is greater than half of the Survivor space, objects whose age is greater than or equal to this age can directly enter the old age without reaching the value set in -XX:MaxTenuringThreshold.

5. Space Allocation Guarantee

When Minor GC occurs, the virtual machine will detect whether the average size of each promotion to the old generation is greater than the remaining space of the old generation. If it is greater, proceed directly. One FUll GC. If it is less than, check whether the HandlerPromotionFailyre setting allows guarantee failure. If it is allowed, only Minor GC will be performed. If it is not allowed, a FUll GC will also be improved. That is to say, when the new generation Eden cannot store the modified object, the object will be stored in the old generation.

3. Commonly used jvm parameter settings

1. -Xms: Initial heap size, default (MinHeapFreeRatio parameter can be adjusted) When the free heap memory is less than 40%, the JVM will increase the heap until -Maximum limit of Xmx.

2.

3. -Xmn: Young generation size (1.4or lator), the size here is (eden+ 2 survivor space). It is different from the New gen shown in jmap -heap.
The entire heap size = young generation size + old generation size + persistent generation size.
After increasing the young generation, the size of the old generation will be reduced. This value has a greater impact on system performance. Sun officially recommends a configuration of 3/8 of the entire heap.

4. -XX:NewSize: Set the young generation size (for 1.3/1.4).

5. -XX:MaxNewSize: The maximum value of the young generation (for 1.3/1.4).

6, -XX:PermSize: Set the initial value of the persistent generation (perm gen).

7, -XX:MaxPermSize: Set the maximum size of the persistent generation.

8. -Xss: The stack size of each thread. After JDK5.0, the stack size of each thread is 1M. In the past, the stack size of each thread was 256K. The memory size required by the application thread can be adjusted. .Under the same physical memory, reducing this value can generate more threads. However, the operating system still has limits on the number of threads in a process and cannot be generated infinitely. The experience value is around 3000~5000.

9, -XX:NewRatio: The ratio of the young generation (including Eden and two Survivor areas) to the old generation (excluding the persistent generation), -XX:NewRatio=4 indicates the difference between the young generation and the old generation The ratio value is 1:4, and the young generation accounts for 1/5 of the entire stack. When Xms=Xmx and Xmn is set, this parameter does not need to be set.

10. -XX:SurvivorRatio: The size ratio of the Eden area and the Survivor area is set to 8, then the ratio of two Survivor areas to one Eden area is 2:8, and one Survivor area accounts for the entire young generation. 1/10.

11. -XX:LargePageSizeInBytes: The size of the memory page cannot be set too large, which will affect the size of Perm.

12. -XX:+DisableExplicitGC: Close System.gc()

13. -XX:MaxTenuringThreshold: The maximum age of garbage. If set to 0, the young generation objects will not pass through Survivor area, directly enter the old generation. For applications with a large number of old generations, efficiency can be improved. If this value is set to a larger value, the young generation objects will be copied multiple times in the Survivor area, so that more objects can be added. The survival time of the young generation increases the probability of being recycled in the young generation. This parameter is only effective in serial GC.

14. -XX:PretenureSizeThreshold: If the object exceeds the size, it is allocated directly in the old generation. The unit byte is invalid when the new generation uses Parallel Scavenge GC. Another situation where it is allocated directly in the old generation is a large array. object, and there are no external reference objects in the array.

15. -XX:TLABWasteTargetPercent: The percentage of TLAB in the eden area.

4. Supplement

The difference between Minor GC and FUll GC:

New generation GC (Minor GC): refers to the garbage collection action that occurs in the new generation, because java objects Large logarithms cannot escape the first round of GC, so Minor GC is used frequently and the recovery speed is generally faster.

Old generation GC (FULL GC/Major GC): refers to the GC that occurs in the old generation. When Major GC appears, it is often accompanied by at least one Minor GC (but not absolutely, in the collection strategy of the ParallelScavenge collector) There is a direct selection process for Major GC). The speed of Major GC is generally more than 10 times slower than Minor GC.

以上是淺談java記憶體分配與回收策略的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具