上一篇咱們講述了Java虛擬機的體系結構和內存模型,那麼咱們就不得不說到內存泄露。你們都知道,Java是從C++的基礎上發展而來的,而C++程序的很大的一個問題就是內存泄露難以解決,儘管Java的JVM有一套本身的垃圾回收機制來回收內存,在大多數的狀況下並不須要java程序開發人員操太多的心,但也是存在泄露問題的,只是比C++小一點。好比說,程序中存在被引用但無用的對象:程序引用了該對象,但後續不會或者不能再使用它,那麼它佔用的內存空間就浪費了。java
咱們先來看看GC是如何工做的:監控每個對象的運行狀態,包括對象的申請、引用、被引用、賦值等,當該對象再也不被引用時,釋放對象(GC本文的重點,不作過多闡述)。不少Java程序員過度依賴GC,但問題的關鍵是不管JVM的垃圾回收機制作得多好,內存總歸是有限的資源,所以就算GC會爲咱們完成了大部分的垃圾回收,但適當地注意編碼過程當中的內存優化仍是很必要的。這樣能夠有效的減小GC次數,同時提高內存利用率,最大限度地提升程序的效率。程序員
整體而言,Java虛擬機的內存優化應從兩方面着手:Java虛擬機和Java應用程序。前者指根據應用程序的設計經過虛擬機參數控制虛擬機邏輯內存分區的大小以使虛擬機的內存與程序對內存的需求相得益彰;後者指優化程序算法,下降GC負擔,提升GC回收成功率。算法
經過參數優化虛擬機內存的參數以下所示:
-Xms
初始Heap大小app
-Xmx
java heap最大值 ide
-Xmn
young generation的heap大小優化
-Xss
每一個線程的Stack大小ui
上面是三個比較經常使用的參數,還有一些:
-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.]編碼
下面所說經過優化程序算法來提升內存利用率,並下降內存風險,徹底是經驗之談,僅供參考,謝謝!spa
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 p_w_picpath = (HtmlImage) img;
String path = p_w_picpath.getSrcAttribute();
String format = path.substring(path.lastIndexOf("."), path.length());
String localPath = "D:/p_w_picpaths/" + MD5Helper.md5(path).replace("\\", ",").replace("/", ",") + format;
File localFile = new File(localPath);
if (!localFile.exists()) {
localFile.createNewFile();
p_w_picpath.saveAs(localFile);
}
p_w_picpath.setAttribute("src", "file:///" + localPath);
localFile = null;
p_w_picpath = 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;
}
PS:若有任何問題,請直接在羣457036818中提出。