項(xiàng)目發(fā)布到Production服務(wù)器上,經(jīng)過一段時(shí)間跟蹤發(fā)現(xiàn)服務(wù)器上項(xiàng)目的內(nèi)存占有量在緩慢增長,但是在本地做壓力時(shí)卻沒有發(fā)現(xiàn)這個(gè)問題,或者雖然做了壓力測試單由于環(huán)境的差異內(nèi)存增長不明顯所以沒有注意。于是就下載了JProfilter安裝到本地的測試服務(wù)器上,運(yùn)行測試發(fā)現(xiàn)有些類的個(gè)數(shù)竟然大于并發(fā)線程的個(gè)數(shù),很是奇怪,經(jīng)分析發(fā)現(xiàn)原來這并發(fā)線程都使用New Class來實(shí)現(xiàn)一些對(duì)底層數(shù)據(jù)或?qū)ο蟮牟僮?,代碼如下:
public void run() {
try {
...
OpenidAccount userData = new OpenidServices().getOpenidAccount(this.openid);
...
} catch (Exception e) {
...
} finally {
...
}
}
以上代碼在線程結(jié)束后,創(chuàng)建的new OpenidServices()對(duì)象 雖然沒有再被其它對(duì)象引用,但是它需要等待JVM回收,這樣當(dāng)有大批量并發(fā)線程出現(xiàn)時(shí)就有可能不能得到及時(shí)釋放,造成系統(tǒng)內(nèi)存大量占用。
分析源碼后發(fā)現(xiàn)可以把這個(gè)方法修改為靜態(tài)方法,
public class OpenidServices {
public static OpenidAccount getOpenidAccount(String openidURL) throws Exception {
if (StringUtils.isNotEmpty(openidURL)) {
...
}else {
return null;
}
}
}
此時(shí)每個(gè)線程的調(diào)用都無需再New一個(gè)新對(duì)象出來,僅需調(diào)用該類的靜態(tài)方法就可以了。
OpenidAccount userData = OpenidServices.getOpenidAccount(this.openid);
所以考試大覺得在多線程代碼中盡可能的減少創(chuàng)建新對(duì)象的個(gè)數(shù),如果可能盡可能使用單例對(duì)象、工具類或靜態(tài)方法,這樣可以減少內(nèi)存的占用量
public void run() {
try {
...
OpenidAccount userData = new OpenidServices().getOpenidAccount(this.openid);
...
} catch (Exception e) {
...
} finally {
...
}
}
以上代碼在線程結(jié)束后,創(chuàng)建的new OpenidServices()對(duì)象 雖然沒有再被其它對(duì)象引用,但是它需要等待JVM回收,這樣當(dāng)有大批量并發(fā)線程出現(xiàn)時(shí)就有可能不能得到及時(shí)釋放,造成系統(tǒng)內(nèi)存大量占用。
分析源碼后發(fā)現(xiàn)可以把這個(gè)方法修改為靜態(tài)方法,
public class OpenidServices {
public static OpenidAccount getOpenidAccount(String openidURL) throws Exception {
if (StringUtils.isNotEmpty(openidURL)) {
...
}else {
return null;
}
}
}
此時(shí)每個(gè)線程的調(diào)用都無需再New一個(gè)新對(duì)象出來,僅需調(diào)用該類的靜態(tài)方法就可以了。
OpenidAccount userData = OpenidServices.getOpenidAccount(this.openid);
所以考試大覺得在多線程代碼中盡可能的減少創(chuàng)建新對(duì)象的個(gè)數(shù),如果可能盡可能使用單例對(duì)象、工具類或靜態(tài)方法,這樣可以減少內(nèi)存的占用量