Java的內存總結
1. 內存分配的基本規則
①.對象優先在新生代Eden分配,當Eden不夠時,將進行一次MinorGC
②.大對象之間進入老年代,比如像很長的字符串,數組等
③.長期存活的對象將進入老年代,每經過一次MinorGC就增加一歲,(默認是15),可以用參數進行調整(-XX:MaxTenuringThreshold=10)
④.並不是必須達到MaxTenuringThreshold才能晉升到老年代,如果在Survivor空間中相同年齡所有對象大小總和大於Survivor空間的一半,則年齡大於或者等於該年齡的對象直接進入老年代
2. java的內存參數配置彙總
JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小
-client
指示VM把應用當成客戶端類程序進行優化,開啓該參數時,對於這類程序而言,內存佔用是最重要的性能標準,遠比高吞吐量重要。
-server
指示VM把應用當成服務器類程序進行優化,該選項適用於高吞吐量比啓動時間和內存佔用更重要的應用程序。
(1)Java堆的初始值、最小值和最大值(新生代和老年代的總和)
-Xms<n>[g|m|k]
-Xmx<n>[g|m|k]
注:如果-Xmx大於-Xms,java的堆大小會依據應用的需求而擴展或縮減。堆的擴展和縮減需要FullGC,所以注重延遲和吞吐量性能的應用,應該吧這兩個值設置成一樣。
(2)設置方法區(永久代)初始值、最小值和最大值
-XX:PermSize
-XX:MaxPermSize
注:如果-XX:MaxPermSize大於-XX:PermSize ,永久代大小會依據應用的需要而擴展或縮減,尤其是在需要家長類或存儲intern String時。永久代的擴展和縮減需要FullGC,所以注重延遲和吞吐量性能的應用,應該把這兩個值設置成一樣。
(3)新生代的初始值、最小值和最大值
-XX:NewSize=<n>[g|m|k]
-XX:MaxNewSize=<n>[g|m|k]
注:如果-XX:MaxNewSize大於-XX:NewSize ,新生代大小會依據應用的需要而擴展或縮減。新生代的擴展和縮減需要FullGC,所以注重延遲和吞吐量性能的應用,應該把這兩個值設置成一樣。
(4)同時設置新生代的初始值、最小和最大值(等同於上面兩個參數設爲一樣)
-Xmn<n>[g|m|k]
(5)設置年老代與年輕代的比值
-XX:NewRatio
注:新生代和老年代的尺寸比,例如n爲3,則比率爲1:3.如果-Xms和-Xmx不同,且希望新生代和老年代的比率爲恆定時,則這個命令比較有用。
(6)設置年輕代的Eden區與Survivor區的大小比值
-XX:SurvivorRatio
注:新生代的單個Survivor區於Eden區的大小的比率
(7)開啓壓縮指針特性
-XX:+UseCompressedOops
注:jdk6Update23之後默認開啓,java引用從32位變爲64位時帶來了性能的損失,他是將64位的指針轉換爲相對於java堆基地址的32位偏移量。當java的-Xmx的值小於32G時可以開啓此選項,提高性能,不夠上限大約爲26GB的時候性能最好。
(8)設置每個線程的棧大小
-Xss<n>[g|m|k]
注:DK5.0以後每個線程堆棧大小爲1M,以前每個線程堆棧大小爲256K。根據應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。
(9)其他配置
①.收集器設置
-XX:+UseSerialGC:設置串行收集器
-XX:+UseParallelGC:設置並行收集器
-XX:+UseParalledlOldGC:設置並行年老代收集器
-XX:+UseConcMarkSweepGC:設置併發收集器
②.垃圾回收統計信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
③.並行收集器設置
-XX:ParallelGCThreads=n:設置並行收集器收集時使用的CPU數。並行收集線程數
-XX:MaxGCPauseMillis=n:設置並行收集最大暫停時間
-XX:GCTimeRatio=n:設置垃圾回收時間佔程序運行時間的百分比。公式爲1/(1+n)
④.併發收集器設置
-XX:+CMSIncrementalMode:設置爲增量模式。適用於單CPU情況。
-XX:ParallelGCThreads=n:設置併發收集器年輕代收集方式爲並行收集時,使用的CPU數。並行收集線程數。
3. 如何提高性能(從內存方面)
①.儘早釋放無用的對象引用(使用臨時變量的時候,讓引用變量在退出活動域後,設置爲null,提高GC回收效率)
②.字符串(儘量使用String str = “hello”;避免使用String str = new String(“hello”);大量使用字符串操作時,儘量避免使用String,要是用StringBuffer/StringBuilder)
③.靜態變量 (儘量少使用靜態變量,因爲靜態變量是全局的,GC不會回收)
④.儘量避免在類的構造函數裏創建、初始化大量的對象(防止在調用其自身類的構造器時造成不必要的內存資源浪費,尤其是大對象,JVM會突然需要大量內存,這時必然會觸發GC優化系統內存環境)
⑤.大集合對象(可以考慮分塊進行處理,處理一塊釋放一塊)
⑥.不要經常在調用方法中創建對象(尤其是忌諱在循環中創建對象,可以適當的使用hashtable創建一組對象容器,然後從容器中去取那些對象,而不是每次new之後又丟棄)
⑦.儘量不用finalize函數(垃圾回收器要回收對象的時候,首先要調用這個類的finalize方法;finealize()會加大GC的工作量,而GC相當耗費系統的計算能力;並且你也不知道finalize方法何時會被調用,是否被調用等)
⑧.分散對象的創建或刪除時間
⑨.能用基本類型就不用包裝類型(基本類型變量的佔用內存資源比包裝類型少的多)
⑩.儘量減少臨時對象的使用(臨時對象在跳出函數調用後,會成爲垃圾,少用臨時變量就相當於減少了垃圾的產生,減少了GC的機會)
⑪.避免使用System.gc()
4. JVM中最大堆大小有三方面限制:
①.操作系統的數據模型(32-bt還是64-bt)限制;32位系統一般限制在1.5G~2G;64位操作系統對內存無限制。
②.系統可用的虛擬內存限制
③.系統可用的物理內存限制
5. 參數使用的5種形式:
①.-XX:+<option> 開啓option參數
②.-XX:-<option> 關閉option參數
③.-XX:<option>=<value> 將option參數設置爲value
④.-<option> 直接啓用參數
⑤.-<option><value> 直接設置option的值爲value
6. JVM的典型配置
java -Xmx5120m –Xms5120m -Xmn2g -Xss128k
注:-Xmx5120m:設置JVM最大可用內存爲5120M。
-Xms5120m:設置JVM初始內存爲5120m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成後JVM重新分配內存。
-Xmn2g:設置年輕代大小爲2G。整個JVM內存大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小爲64m,所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。
-Xss128k:設置每個線程的棧大小。JDK5.0以後每個線程堆棧大小爲1M,以前每個線程堆棧大小爲256K。根據應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。
java -Xmx3550m -Xms3550m -Xss128k
-XX:NewRatio=4
-XX:SurvivorRatio=4
-XX:MaxPermSize=16m
-XX:MaxTenuringThreshold=0
注:-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置爲4,則年輕代與年老代所佔比值爲1:4,年輕代佔整個堆棧的1/5
-XX:SurvivorRatio=4:設置年輕代中Eden區與Survivor區的大小比值。設置爲4,則兩個Survivor區與一個Eden區的比值爲2:4,一個Survivor區佔整個年輕代的1/6
-XX:MaxPermSize=16m:設置持久代大小爲16m。
-XX:MaxTenuringThreshold=0:設置年輕代最大年齡。如果設置爲0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設置爲一個較大值,則年輕代對象會在Survivor區進行多次複製,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收