這篇文章給大家分享的是有關(guān)Java中由substring方法引發(fā)內(nèi)存泄漏的示例分析的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
成都創(chuàng)新互聯(lián)長期為超過千家客戶提供的網(wǎng)站建設(shè)服務(wù),團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為景泰企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè),景泰網(wǎng)站改版等技術(shù)服務(wù)。擁有10年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
內(nèi)存溢出(out of memory ) :通俗的說就是內(nèi)存不夠用了,比如在一個無限循環(huán)中不斷創(chuàng)建一個大的對象,很快就會引發(fā)內(nèi)存溢出。
內(nèi)存泄漏(leak of memory) :是指為一個對象分配內(nèi)存之后,在對象已經(jīng)不在使用時未及時的釋放,導(dǎo)致一直占據(jù)內(nèi)存單元,使實際可用內(nèi)存減少,就好像內(nèi)存泄漏了一樣。
由substring方法引發(fā)的內(nèi)存泄漏
substring(int beginIndex, int endndex )是String類的一個方法,但是這個方法在JDK6和JDK7中的實現(xiàn)是完全不同的(雖然它們都達(dá)到了同樣的效果)。了解它們實現(xiàn)細(xì)節(jié)上的差異,能夠更好的幫助你使用它們,因為在JDK1.6中不當(dāng)使用substring會導(dǎo)致嚴(yán)重的內(nèi)存泄漏問題。
1、substring的作用
substring(int beginIndex, int endIndex)方法返回一個子字符串,從父字符串的beginIndex開始,結(jié)束于endindex-1。父字符串的下標(biāo)從0開始,子字符串包含beginIndex而不包含endIndex
String x= "abcdef"; x= str.substring(1,3); System.out.println(x);
上述程序的輸出是“bc”
2、實現(xiàn)原理
String類是不可變變,當(dāng)上述第二句中x被重新賦值的時候,它會指向一個新的字符串對象。然而,沒有準(zhǔn)確說明的或者代表堆中發(fā)生的實際情況,當(dāng)substring被調(diào)用的時候真正發(fā)生的才是這兩者的差別。
JDK6中的substring實現(xiàn)
String對象被當(dāng)作一個char數(shù)組來存儲,在String類中有3個域:char[] value、int offset、int count,分別用來存儲真實的字符數(shù)組,數(shù)組的起始位置,String的字符數(shù)。由這3個變量就可以決定一個字符串。當(dāng)substring方法被調(diào)用的時候,它會創(chuàng)建一個新的字符串,但是上述的char數(shù)組value仍然會使用原來父數(shù)組的那個value。父數(shù)組和子數(shù)組的唯一差別就是count和offset的值不一樣。
看一下JDK6中substring的實現(xiàn)源碼:
public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex > endIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value); //使用的是和父字符串同一個char數(shù)組value }
String(int offset, int count, char value[]) { this.value = value; this.offset = offset; this.count = count; }
String str = "abcdefghijklmnopqrst"; String sub = str.substring(1, 3); str = null;
這段簡單的程序有兩個字符串變量str、sub。sub字符串是由父字符串str截取得到的,假如上述這段程序在JDK1.6中運行,我們知道數(shù)組的內(nèi)存空間分配是在堆上進(jìn)行的,那么sub和str的內(nèi)部char數(shù)組value是公用了同一個,也就是上述有字符a~字符t組成的char數(shù)組,str和sub唯一的差別就是在數(shù)組中其實beginIndex和字符長度count的不同。在第三句,我們使str引用為空,本意是釋放str占用的空間,但是這個時候,GC是無法回收這個大的char數(shù)組的,因為還在被sub字符串內(nèi)部引用著,雖然sub只截取這個大數(shù)組的一小部分。當(dāng)str是一個非常大字符串的時候,這種浪費是非常明顯的,甚至?xí)硇阅軉栴},解決這個問題可以是通過以下的方法:
利用的就是字符串的拼接技術(shù),它會創(chuàng)建一個新的字符串,這個新的字符串會使用一個新的內(nèi)部char數(shù)組存儲自己實際需要的字符,這樣父數(shù)組的char數(shù)組就不會被其他引用,令str=null,在下一次GC回收的時候會回收整個str占用的空間。但是這樣書寫很明顯是不好看的,所以在JDK7中,substring 被重新實現(xiàn)了。
JDK7中的substring實現(xiàn)
在JDK7中改進(jìn)了substring的實現(xiàn),它實際是為截取的子字符串在堆中創(chuàng)建了一個新的char數(shù)組用于保存子字符串的字符。
查看JDK7中String類的substring方法的實現(xiàn)源碼:
public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); }
Arrays類的copyOfRange方法:
public static char[] copyOfRange(char[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); char[] copy = new char[newLength]; //是創(chuàng)建了一個新的char數(shù)組 System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; }
可以發(fā)現(xiàn)是去為子字符串創(chuàng)建了一個新的char數(shù)組去存儲子字符串中的字符。這樣子字符串和父字符串也就沒有什么必然的聯(lián)系了,當(dāng)父字符串的引用失效的時候,GC就會適時的回收父字符串占用的內(nèi)存空間。
感謝各位的閱讀!關(guān)于“Java中由substring方法引發(fā)內(nèi)存泄漏的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
網(wǎng)站題目:Java中由substring方法引發(fā)內(nèi)存泄漏的示例分析
本文來源:http://jinyejixie.com/article0/pgigio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計、做網(wǎng)站、搜索引擎優(yōu)化、標(biāo)簽優(yōu)化、建站公司、網(wǎng)頁設(shè)計公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)