Java虛擬機器記憶體優化實踐
前面一篇文章介紹了Java虛擬機器的體系結構和記憶體模型,既然提到記憶體,就不得不說到記憶體洩露。眾所周知,Java是從C++的基礎上發展而來的,而C++程式的很大的一個問題就是記憶體洩露難以解決,儘管Java的JVM有一套自己的垃圾回收機制來回收記憶體,在許多情況下並不需要java程式開發人員操太多的心,但也是存在洩露問題的,只是比C++小一點。比如說,程式中存在被引用但無用的物件:程式引用了該物件,但後續不會或者不能再使用它,那麼它佔用的記憶體空間就浪費了。
我們先來看看GC是如何工作的:監控每一個物件的執行狀態,包括物件的申請、引用、被引用、賦值等,當該物件不再被引用時,釋放物件(GC本文的重點,不做過多闡述)。很多Java程式設計師過分依賴GC,但問題的關鍵是無論JVM的垃圾回收機制做得多好,記憶體總歸是有限的資源,因此就算GC會為我們完成了大部分的垃圾回收,但適當地注意編碼過程中的記憶體優化還是很必要的。這樣可以有效的減少GC次數,同時提升記憶體利用率,最大限度地提高程式的效率。
總體而言,Java虛擬機器的記憶體優化應從兩方面著手:Java虛擬機器和Java應用程式。前者指根據應用程式的設計通過虛擬機器引數控制虛擬機器邏輯記憶體分割槽的大小以使虛擬機器的記憶體與程式對記憶體的需求相得益彰;後者指優化程式演算法,降低GC負擔,提高GC回收成功率。
通過引數優化虛擬機器記憶體的引數如下所示:
Xms
初始Heap大小
Xmx
java heap最大值
Xmn
young generation的heap大小
Xss
每個執行緒的Stack大小
上面是三個比較常用的引數,還有一些:
XX:MinHeapFreeRatio=40
Minimum percentage of heap free after GC to avoid expansion.
XX:MaxHeapFreeRatio=70
Maximum percentage of heap free after GC to avoid shrinking.
XX:NewRatio=2
Ratio of new/old generation sizes. [Sparc -client:8; x86 -server:8; x86 -client:12.]-client:8 (1.3.1+), x86:12]
XX:NewSize=2.125m
Default size of new generation (in bytes) [5.0 and newer: 64 bit VMs are scaled 30% larger; x86:1m; x86, 5.0 and older: 640k]
XX:MaxNewSize=
Maximum size of new generation (in bytes). Since 1.4, MaxNewSize is computed as a function of NewRatio.
XX:SurvivorRatio=25
Ratio of eden/survivor space size [Solaris amd64: 6; Sparc in 1.3.1: 25; other Solaris platforms in 5.0 and earlier: 32]
XX:PermSize=
Initial size of permanent generation
XX:MaxPermSize=64m
Size of the Permanent Generation. [5.0 and newer: 64 bit VMs are scaled 30% larger; 1.4 amd64: 96m; 1.3.1 -client: 32m.]
下面所說通過優化程式演算法來提高記憶體利用率,並降低記憶體風險,完全是經驗之談,僅供參考,如有不妥,請指正,謝謝!
1.儘早釋放無用物件的引用(XX = null;)
看一段程式碼:
public List<PageData> parse(HtmlPage page) { List<PageData> list = null; try { List valueList = page.getByXPath(config.getContentXpath()); if (valueList == null || valueList.isEmpty()) { return list; } //需要時才建立物件,節省記憶體,提高效率 list = new ArrayList<PageData>(); PageData pageData = new PageData(); StringBuilder value = new StringBuilder(); for (int i = 0; i < valueList.size(); i++) { HtmlElement content = (HtmlElement) valueList.get(i); DomNodeList<HtmlElement> imgs = content.getElementsByTagName("img"); if (imgs != null && !imgs.isEmpty()) { for (HtmlElement img : imgs) { try { HtmlImage image = (HtmlImage) img; String path = image.getSrcAttribute(); String format = path.substring(path.lastIndexOf("."), path.length()); String localPath = "D:/images/" + MD5Helper.md5(path).replace("\\", ",").replace("/", ",") + format; File localFile = new File(localPath); if (!localFile.exists()) { localFile.createNewFile(); image.saveAs(localFile); } image.setAttribute("src", "file:///" + localPath); localFile = null; image = null; img = null; } catch (Exception e) { } } //這個物件以後不會在使用了,清除對其的引用,等同於提前告知GC,該物件可以回收了 imgs = null; } String text = content.asXml(); value.append(text).append("<br/>"); valueList=null; content = null; text = null; } pageData.setContent(value.toString()); pageData.setCharset(page.getPageEncoding()); list.add(pageData); //這裡 pageData=null; 是沒用的,因為list仍然持有該物件的引用,GC不會回收它 value=null; //這裡可不能 list=null; 因為list是方法的返回值,否則你從該方法中得到的返回值永遠為空,而且這種錯誤不易被發現、排除 } catch (Exception e) { } return list; }
2.謹慎使用集合資料型別,如陣列,樹,圖,連結串列等資料結構,這些資料結構對GC來說回收更復雜。
3.避免顯式申請陣列空間,不得不顯式申請時,儘量準確估計其合理值。
4.儘量避免在類的預設構造器中建立、初始化大量的物件,防止在呼叫其自類的構造器時造成不必要的記憶體資源浪費
5.儘量避免強制系統做垃圾記憶體的回收,增長系統做垃圾回收的最終時間
6.儘量做遠端方法呼叫類應用開發時使用瞬間值變數,除非遠端呼叫端需要獲取該瞬間值變數的值。
7.儘量在合適的場景下使用物件池技術以提高系統效能
相關文章
- JAVA 虛擬機器可用記憶體Java虛擬機記憶體
- Java虛擬機器12:Java記憶體模型Java虛擬機記憶體模型
- Java 虛擬機器之三:Java虛擬機器的記憶體結構Java虛擬機記憶體
- Java虛擬機器之記憶體區域Java虛擬機記憶體
- Java虛擬機器4:記憶體溢位Java虛擬機記憶體溢位
- Java虛擬機器學習 - 記憶體調優Java虛擬機機器學習記憶體
- win10虛擬記憶體如何優化_win10怎麼優化虛擬記憶體Win10記憶體優化
- 小試Java虛擬機器記憶體管理(Java 8)Java虛擬機記憶體
- 深入理解JVM虛擬機器11:Java記憶體異常原理與實踐JVM虛擬機Java記憶體
- Java虛擬機器記憶體模型學習筆記Java虛擬機記憶體模型筆記
- 《深入理解Java虛擬機器》個人讀書總結——JAVA虛擬機器記憶體Java虛擬機記憶體
- 【Java基礎】實體記憶體&虛擬記憶體Java記憶體
- Java虛擬機器記憶體分配與回收策略Java虛擬機記憶體
- Java虛擬機器記憶體區域詳解Java虛擬機記憶體
- Java虛擬機器記憶體區域劃分Java虛擬機記憶體
- eclipse 設定java虛擬機器記憶體EclipseJava虛擬機記憶體
- Java虛擬機器:JVM記憶體分代策略Java虛擬機JVM記憶體
- Java虛擬機器7:記憶體分配原則Java虛擬機記憶體
- Java8虛擬機器(JVM)記憶體溢位實戰Java虛擬機JVM記憶體溢位
- Java虛擬機器2:Java記憶體區域及物件Java虛擬機記憶體物件
- [Java虛擬機器]Java記憶體模型與執行緒Java虛擬機記憶體模型執行緒
- java虛擬機器記憶體的各個區域Java虛擬機記憶體
- Java虛擬機器:記憶體管理與執行引擎Java虛擬機記憶體
- java虛擬機器執行時記憶體分割槽Java虛擬機記憶體
- 【深入Java虛擬機器】之一:Java記憶體區域與記憶體溢位Java虛擬機記憶體溢位
- App記憶體優化-實踐APP記憶體優化
- Java虛擬機器08——Java記憶體模型與執行緒Java虛擬機記憶體模型執行緒
- Java虛擬機器系列之Java記憶體結構簡介Java虛擬機記憶體
- 【Java 虛擬機器筆記】記憶體分配策略相關整理Java虛擬機筆記記憶體
- 實體記憶體和虛擬記憶體記憶體
- Java虛擬機器的記憶體空間有幾種Java虛擬機記憶體
- Java虛擬機器的記憶體空間有幾種!Java虛擬機記憶體
- 帶你清晰認識,Java虛擬機器記憶體管理!Java虛擬機記憶體
- 面試準備之java虛擬機器記憶體結構面試Java虛擬機記憶體
- 深入理解虛擬機器之Java記憶體區域虛擬機Java記憶體
- Java虛擬機器的記憶體是如何分佈的Java虛擬機記憶體
- 《深入java虛擬機器》讀書筆記之Java記憶體區域Java虛擬機筆記記憶體
- Java虛擬機器11:執行期優化Java虛擬機優化