java程式效能優化讀書筆記-垃圾回收
衡量系統性能的點
- 執行速度:即響應時間
- 記憶體分配:記憶體分配是否合理,是否過多消耗記憶體或者存在記憶體洩露
- 啟動時間:程式從啟動到正常處理業務需要的時間
- 負載承受能力:當系統壓力上升,系統執行速度和響應時間上升曲線是否平緩
系統調優層次
- 系統設計調優
- 程式碼調優
- jvm調優
- 資料庫調優
- 作業系統調優
垃圾回收基礎
垃圾回收演算法:
引用計數法:每個物件都有一個引用計數器,當被一個物件引用的時候計數器+1,當引用失效的時候計數器-1,當計數器為0的時候就可以被回收掉。這種演算法的缺陷是,不能解決迴圈引用的問題,當A\B相互引用的時候,各自的引用計數器都為1,但是他們都沒有被第三個物件所引用,所以是可以被回收掉的。由於由這種缺陷,引用計數法不適合JVM的垃圾回收。
標記-清除演算法:標記清除法是現代垃圾回收演算法思想的基礎。從根節點開始,通過標記根節點開始所有可達的物件,標記完成後,對未標記的物件進行清除。這種演算法的缺點是,清除後會出現不連續的記憶體區域。不連續的記憶體空間效率比連續的記憶體空間要低。
複製演算法:把記憶體區域分成2塊。一塊是正在使用的,一塊是沒有在使用的。當進行垃圾回收的時候,把存活的物件從正在使用的區域複製到非正在使用的區域,然後清除正在使用區域的所有物件,交換2個記憶體的角色完成垃圾回收。這樣可用區域的記憶體就連續了。如果垃圾物件多餘存活物件,這種方式效果就比較好。
java新生代垃圾序列回收器使用了複製演算法的思想。標記壓縮演算法:適合老年代回收演算法。在標記清除法的基礎上做了優化。當需要回收的物件比較少的時候,這種演算法比較高效。標記完後,把存活的物件壓縮到記憶體的一端,然後把垃圾物件清理,這樣就避免了不連續區域。
增量演算法:對於大部分垃圾回收演算法,垃圾回收的時候會stop the world,所有應用的執行緒都會掛起,導致停頓。增加的話,是分割槽域垃圾回收,減少垃圾回收的範圍,然後再間歇執行下應用程式。
分代:將記憶體區域根據物件特點分成幾塊,不同的塊使用不同的垃圾回收演算法。在Hot Spot虛擬機器中,所有新建的物件都放到新生代,當一個物件經過幾次回收仍然存活就放入老年代
記憶體區域 | 使用的演算法 |
---|---|
新生代 | 複製演算法 |
老年代 | 標記壓縮演算法 |
JVM調優常見案例
大物件進入老年代:新生的大物件如果放在新生帶可能會擾亂新生代的記憶體回收,因為新生代如果被大物件擠滿了,新產生的物件都會被擠過去老年代, -XX:PretenureSizeThreshold 設定大物件直接進入老年代的閾值。 如果進入了老年代,又比較短命的話,標記壓縮演算法又會很不利,所以如果短命的大物件太多,對垃圾回收是一種災難。
設定進入老年代的年齡:新生代進入老年代和年齡有關。新物件會放在eden區,如果經過一次回收仍然存活,則被放入survivior區,物件年齡增加1。如果年齡達到的閾值就會被挪到老年代。-XX:MaxTenuringThreshold 設定最大年齡。
穩定與震盪的堆大小: 穩定的堆大小會減少GC的次數,因此有的人會設定最小堆記憶體和最大堆記憶體成一樣的值。但是GC堆大的話也會影響單次GC的時間。因此出了Xmx和Xms外還提供了以下引數。當Xmx和Xms一樣的時候以下引數無效。
引數 | 作用 |
---|---|
-XX:MinHeapFreeRatio:40 | 堆空間最小空閒比例,預設是40。當空閒的小於40%的時候,會擴大堆空間,確保程式空閒的時候震盪不會太大。 |
-XX:MaxHeapFreeRatio:70 | 堆空間最大空閒比例,預設是70。當空閒的空間大於70%的時候,會壓縮堆空間。 |
實用案例
- 吞吐量優先案例(32核,4G)
啟動引數 | 引數解析 |
---|---|
-Xmx3800m -Xms3800m | 減少堆震盪和頻繁GC。吞吐量大,記憶體一般都會維持在較高水平 |
-Xss128k | 減少執行緒棧大小,剩餘的系統記憶體支援更多的執行緒。 |
-Xmn2g | 設定新生代大小 |
-XX:UseParallelGC | 新生代使用並行回收器 |
-XX:ParallelGCThreads=20 | 設定垃圾回收執行緒總數 |
-XX:UseParallelOldGC | 老年代也使用並行回收器 |
使用大葉案例:在Solaris系統中,jvm支援大頁使用 -XX:LargePageSizeInBytes=256m
降低停頓案例
啟動引數 | 引數解析 |
---|---|
-XX:ParallelGCThreads=20 | 設定垃圾回收執行緒總數 |
-XX:UseParallelGC | 新生代使用並行回收器 |
-XX:UseConcMarkSweepGC | 老年代使用CMS收集器降低停頓 |
-XX:SurvivorRatio=8 | eden區:survivor區 = 8:1 稍大的survivor區,可以提高在新生代回收宣告週期較短的物件的可能性,避免進入老年代 |
-XX:TargetSurvivor=90 | 設定survivor的可使用率為90%,預設是50%,提高了survivor區的實用率 |
-XX:MaxTenuringThreshold=31 | 設定年輕代進入老年代的年齡,預設是15,這裡設定成31,儘可能地將物件儲存在新生代 |