如何造成内存泄漏
這將是一個(gè)相當(dāng)邪惡的職位-當(dāng)您確實(shí)希望使某人的生活陷入困境時(shí),您將在谷歌上搜索。 在Java開(kāi)發(fā)領(lǐng)域,內(nèi)存泄漏只是您在這種情況下會(huì)引入的錯(cuò)誤類(lèi)型。 為您的受害者保證幾天甚至幾周的辦公室不眠之夜。
我們將在這篇文章中描述兩次泄漏。 兩者都很容易理解和復(fù)制。 泄漏源于現(xiàn)實(shí)世界中的案例研究,但為清楚起見(jiàn),我們提取了演示案例,以使您更短,更簡(jiǎn)單。 但是請(qǐng)放心–在我們已經(jīng)看到并修復(fù)了數(shù)百個(gè)泄漏之后–與演示的情況類(lèi)似的情況比您預(yù)期的更普遍。
第一個(gè)闖入環(huán)的參賽者–臭名昭著的HashSet / HashMap解決方案,其中使用的鍵不具有或具有不正確的equals()/ hashCode( )解決方案。
當(dāng)您執(zhí)行上面的代碼時(shí),您希望它可以永遠(yuǎn)運(yùn)行而不會(huì)出現(xiàn)任何問(wèn)題-畢竟,內(nèi)置的幼稚緩存解決方案應(yīng)該只擴(kuò)展到10,000個(gè)元素,然后停止增長(zhǎng),因?yàn)樗墟I都已經(jīng)存在于HashMap中 。 但是,情況并非如此-元素會(huì)繼續(xù)添加,因?yàn)镵ey類(lèi)在其hashCode()旁邊不包含適當(dāng)?shù)膃quals()實(shí)現(xiàn) 。 該解決方案很容易–與以下示例類(lèi)似,添加equals()方法的實(shí)現(xiàn),您很高興。 但是,在設(shè)法找到原因之前,您肯定已經(jīng)失去了一些寶貴的腦細(xì)胞。
@Override public boolean equals(Object o) {boolean response = false;if (o instanceof Key) {response = (((Key)o).id).equals(this.id);}return response; }讓您的朋友保持清醒的第二個(gè)問(wèn)題-一些操作中的字符串處理。 像魅力一樣工作,尤其是與JVM版本差異結(jié)合使用時(shí)。 在JDK 7u6中更改了 String內(nèi)部構(gòu)件的工作方式,因此,如果您設(shè)法找到僅次要版本導(dǎo)致生產(chǎn)和登臺(tái)不同的環(huán)境,那么您已經(jīng)準(zhǔn)備就緒 。 向您的朋友投擲類(lèi)似于以下代碼的代碼,以進(jìn)行調(diào)試,并想知道為什么問(wèn)題不在生產(chǎn)中出現(xiàn)在其他任何地方。
class Stringer {static final int MB = 1024*512;static String createLongString(int length){StringBuilder sb = new StringBuilder(length);for(int i=0; i < length; i++)sb.append('a');sb.append(System.nanoTime());return sb.toString();}public static void main(String[] args){List<string> substrings = new ArrayList<string>();for(int i=0; i< 100; i++){String longStr = createLongString(MB);String subStr = longStr.substring(1,10);substrings.add(subStr);}} }上面的代碼中發(fā)生的事情–當(dāng)它在預(yù)JDK 7u6上運(yùn)行時(shí),返回的子字符串在下面保留了對(duì)?1MB大字符串的引用。 因此,當(dāng)使用-Xmx100m運(yùn)行示例時(shí),您將遇到意外的OutOfMemoryException。 將此與平臺(tái)差異結(jié)合起來(lái),在您正在嘗試的環(huán)境中使用不同的JDK版本,第一批白發(fā)將蓬勃發(fā)展。 現(xiàn)在,如果您想掩蓋自己的足跡,我們可以將一些更高級(jí)的概念添加到產(chǎn)品組合中,例如
- 在其他類(lèi)加載器中加載已損壞的代碼,并在丟棄原始類(lèi)加載器后模仿類(lèi)加載器泄漏 ,保留對(duì)加載的類(lèi)的引用。
- 將有問(wèn)題的代碼隱藏到finalize()方法中,使癥狀真正不可預(yù)測(cè)
- 將長(zhǎng)時(shí)間運(yùn)行的線程的棘手組合扔掉,這些線程將某些東西存儲(chǔ)在ThreadPool所訪問(wèn)的ThreadLocals中–受控制的應(yīng)用程序線程
希望我們能給您帶來(lái)一些思考,并為您下次生氣時(shí)提供一些技巧。 無(wú)數(shù)小時(shí)的核心調(diào)試保證。 除非您的朋友使用Plumbr ,否則當(dāng)然會(huì)為他找到泄漏。 但是公然的市場(chǎng)營(yíng)銷(xiāo)方面,我希望我們能夠在兩個(gè)簡(jiǎn)單的例子中證明在Java中創(chuàng)建內(nèi)存泄漏有多么容易。 你們中的大多數(shù)人都經(jīng)歷了追蹤這樣一個(gè)錯(cuò)誤的難度。 因此,如果您喜歡這篇文章,請(qǐng)訂閱我們的Twitter feed,以得到有關(guān)我們未來(lái)有關(guān)JVM性能調(diào)整的內(nèi)容的警報(bào)。
翻譯自: https://www.javacodegeeks.com/2013/04/how-to-create-a-memory-leak.html
總結(jié)
- 上一篇: Spring Java配置
- 下一篇: 发布Disruptor 3.0.0