堆配置
-Xms:初始堆大小
-Xms:最大堆大小
-XX:NewSize=n:設置年輕代大小
-XX:NewRatio=n:設置年輕代和年老代的比值。如:為3表示年輕代和年老代比值為1:3,年輕代占整個年輕代年老代和的1/4
-XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個。如3表示Eden: 3 Survivor:2,一個Survivor區占整個年輕代的1/5
-XX:MaxPermSize=n:設置持久代大小
說明:
1、一般初始堆和最大堆設置一樣,因為:現在內存不是什么稀缺的資源,但是如果不一樣,從初始堆到最大堆的過程會有一定的性能開銷,所以一般設置為初始堆和最大堆一樣。64位系統理論上可以設置為無限大,但是一般設置為4G,因為如果再大,JVM進行垃圾回收出現的暫停時間會比較長,這樣全GC過長,影響JVM對外提供服務,所以不能太大。一般設置為4G。
2、-XX:NewRaio和-XX:SurvivorRatio這兩個參數,都是設置年輕代和年老代的大小的,設置一個即可,第一是設置年輕代的大小,第二個是設置比值,理論上設置一個既可以滿足需求
收集器設置:
-XX:+UseSerialGC:設置串行收集器
-XX:+UseParallelGC:設置並行收集器
-XX:+UseParalledlOldGC:設置並行年老代收集器
-XX:+UseConcMarkSweepGC:設置並發收集器
垃圾回收統計信息
打印GC回收的過程日志信息
-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數。並行收集線程數
典型配置舉例
以下配置主要針對分代收集回收算法而言
堆大小設置
年輕代的設置很關鍵
JVM中最大堆大小有三方面限制:相關操作系統的數據模型(32bit還是64bit)限制:系統的可用虛擬內存限制;系統的可用物理內存限制。32位系統下,一般限制在1.5G-2G;64位操作系統對內存沒有限制。在Windows Server 2003系統,3.5G物理內存,JDK5.0下測試,最大設置為1478m。
典型設置:
java-Xmx3550m -Xms3550m-Xmn2g -Xss128k
-Xmx3550m:設置JVM最大可用內存為3550m
-Xms3550m:設置JVM初始內存為3550m,此值可以設置-Xmx相同,以避免每次垃圾回收完成以后JVM重新分配內存
-Xmn2g:設置年輕代大小為2G。整個堆大小=年輕代大小+年老代大小+持久代大小。持久代一般固定為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區進行多次復制,這樣可以增加對象在年輕代的存活時間。
回收器的選擇
JVM給了三種選擇:串行收集器,並行收集器,並發收集器,但是串行收集器只適用於小數據量的情況,一般不考慮使用了,所以這里只針對並行收集器和並發收集器。默認情況下,JDK5.0以前是使用的串行收集器,如果想使用其他收集器需要在啟動時加入相應的參數,JDK5.0以后,JVM會根據系統當前的配置進行判斷
吞吐量優先的並行收集器
並行收集器主要以到達一定的吞吐量為目標,適用於后台處理
java -Xmx3550m-Xms3550m-Xss128k-XX:+UseParallelGC
-XX:ParallelGCThreads=20
-XX:+UseParallelGC:選擇垃圾收集器為並行收集器。次配置僅對年輕代有效。即上述配置下,年輕代使用並行收集,而年老代仍舊使用串行收集。
-XX:PARALLELgcThreads=20:配置並行收集器的線程數,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相同。
-XX:+UseParallelOldGC:配置年老代來及收集方式為並行收集,JDK6.0支持對年老代並行收集
-XX:MaxGCPauseMillis=100:設置每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值
-XX:+UseAdaptiveSizePolicy:設置此選項以后,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低響應時間或者收集頻率等,此值建議使用並行收集器時,一直打開
響應時間優先的並發收集器
並發收集器主要是保證系統的響應時間,減少垃圾收集時的停頓時間。適用於應用服務器、電信領域等。
-XX:CMSFullGCsBeforeCompaction=5
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction:由於並發收集器不對內存空間進行壓縮、整理、所以運行一段時間以后會產生“碎片”,使得運行效率降低。此值設置運行多少次GC以后對內存空間進行壓縮、整理
-XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,但是可以消除碎片
調優總結:
年輕代大小選擇
響應時間優先的應用:盡可能設置大,直到接近系統的最低響應時間限制(根據實際情況選擇)。在此種情況下,年輕代收集發生的頻率也是最小的。同時減少到達年老代的對象。
吞吐量優先的應用:盡可能的設置大,可能到達Gbit的成都,因為對響應時間沒有要求,垃圾收集可以並行進行,一般適合8核CPU以上應用。
年老代大小選擇
響應時間優先的應用:年老代使用並發收集器,所以其大小需要小心設置,一般要考慮並發會話率和會話持續時間等一些參數。如果堆設置小了,可能會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。最優化的方案,一般需要參考一下數據獲得:
1、並發垃圾收集信息
2、持久代並發收集次數
3、傳統GC信息
4、花在年輕代和年老代回收上的時間比例減少年輕代和年老代花費的時間,一般會提高應用的效率
吞吐量優先的應用
一般吞吐量優先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以盡可能回收掉大部分短期對象,減少中期對象,而年老代盡存放長期存活的對象
較小堆引起的碎片問題
因為年老代的並發收集器使用標記、清除算法,所以不會對堆進行壓縮。當收集器回收時,他會把相鄰的空間進行合並,這樣可以分配給較大的對象。但是當堆空間較小時,運行一段時間以后,就會出現“碎片”,如果並發收集器找不到足夠的空間,那么並發收集器將會停止,然后使用傳統的標記、清除方式進行回收。如果出現“碎片”,可能需要進行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用並發收集器時,開啟對年老代的壓縮
-XX:CMSFullGCsBeforeCompaction=0:上面配置開啟的情況下,這里設置多少次FullGc后,對年老代進行壓縮
調優方法
調優工具
Jconsole,jProfile,VisualVM
Jconsole:jdk自帶, 功能簡單,但是可以再系統有一定負荷的情況下使用,對垃圾回收算法有很詳細的跟蹤。
JProfiler:商業軟件,需要付費,但是功能強大
VisualVM:JDK自帶,功能強大,與Jprofiler類似,推薦
如何調優
觀察內存釋放情況、集合類檢查,對象樹
上面這些調優工具都提供了強大的功能,但是總的來說一般分為以下幾類功能:
1、堆的信息查看(年輕代、年老代、持久代分配)
2、提供即時的垃圾回收功能呢
3、垃圾監控,長時間監控
內存泄露檢查
一般就是根據垃圾回收前后情況對比,同時根據對象引用情況(常見的集合對象引用)分析,基本都可以找到泄漏點。
持久代沾滿處理:
1、-XX:MaxPermSize=16m
2、換JDK比如:JRocket
系統內存被沾滿:
一般是因為沒有足夠的資源產生線程造成的,系統創建線程時,除了要在Java堆中分配內存外,操作系統本身也需要分配資源來創建線程。因此,當線程數量大的一定程度以后,堆中或許還有空間,但是操作系統分配不出資源來了,出現異常。
分配給Java虛擬機的內存越多,系統剩余的資源就越少,因此,當系統內存固定時,分配給Java虛擬機的內存越多,那么,系統總共能夠產生的線程也就越少,兩者成反比。同事,可以通過修改-Xss來減少分配給單個線程的空間,也可以增加系統總共生產的線程數。
java程序內存問題的診斷方法:
1、jstat可以查看垃圾回收情況:jstat -gcutil pid
2、jmap可以將java內存dump出來
3、jstack -l 進程id
4、eclipse插件MAT可以有效的分析內存占用情況
jmap -h
查看jmap的命令參數,幫助查看堆信息

最大線程數,一般的機器300-500不錯了,淘寶曾經調優過1500,不過不清楚是如何調的。