Java中典型的內(nèi)存泄露問(wèn)題和解決方法
Q:在Java中怎么可以產(chǎn)生內(nèi)存泄露?
A:Java中,造成內(nèi)存泄露的原因有很多種。典型的例子是一個(gè)沒有實(shí)現(xiàn)hasCode和
equals方法的Key類在HashMap中保存的情況。最后會(huì)生成很多重復(fù)的對(duì)象。所有的內(nèi)存泄露
最后都會(huì)拋出OutOfMemoryError異常,下面通過(guò)一段簡(jiǎn)短的通過(guò)無(wú)限循環(huán)模擬內(nèi)存泄露
的例子說(shuō)明一下。
import java.util.HashMap;
import java.util.Map;
public class MemoryLeak {
public static void main(String[] args) {
Map<Key, String> map = new HashMap<Key, String>(1000);
int counter = 0;
while (true) {
// creates duplicate objects due to bad Key class
map.put(new Key("dummyKey"), "value");
counter++;
if (counter % 1000 == 0) {
System.out.println("map size: " + map.size());
System.out.println("Free memory after count " + counter
+ " is " + getFreeMemory() + "MB");
sleep(1000);
}
}
}
// inner class key without hashcode() or equals() -- bad implementation
static class Key {
private String key;
public Key(String key) {
this.key = key;
}
}
//delay for a given period in milli seconds
public static void sleep(long sleepFor) {
try {
Thread.sleep(sleepFor);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//get available memory in MB
public static long getFreeMemory() {
return Runtime.getRuntime().freeMemory() / (1024 * 1024);
}
}
結(jié)果如下:
map size: 1000
Free memory after count 1000 is 4MB
map size: 2000
Free memory after count 2000 is 4MB
map size: 1396000
Free memory after count 1396000 is 2MB
map size: 1397000
Free memory after count 1397000 is 2MB
map size: 1398000
Free memory after count 1398000 is 2MB
map size: 1399000
Free memory after count 1399000 is 1MB
map size: 1400000
Free memory after count 1400000 is 1MB
map size: 1401000
Free memory after count 1401000 is 1MB
.....
.....
map size: 1452000
Free memory after count 1452000 is 0MB
map size: 1453000
Free memory after count 1453000 is 0MB
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.addEntry(HashMap.java:753)
at java.util.HashMap.put(HashMap.java:385)
at MemoryLeak.main(MemoryLeak.java:10)
Q:怎么解決上面的內(nèi)存泄露?
A:實(shí)現(xiàn)Key類的equals和hasCode方法。
.....
static class Key {
private String key;
public Key(String key) {
this.key = key;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Key)
return key.equals(((Key) obj).key);
else
return false;
}
@Override
public int hashCode() {
return key.hashCode();
}
}
.....
重新執(zhí)行程序會(huì)得到如下結(jié)果:
map size: 1
Free memory after count 1000 is 4MB
map size: 1
Free memory after count 2000 is 4MB
map size: 1
Free memory after count 3000 is 4MB
map size: 1
Free memory after count 4000 is 4MB
...
Free memory after count 73000 is 4MB
map size: 1
Free memory after count 74000 is 4MB
map size: 1
Free memory after count 75000 is 4MB
Q:在實(shí)際場(chǎng)景中,你怎么查找內(nèi)存泄露?
A:通過(guò)以下代碼獲取線程ID
C:\>jps
5808 Jps
4568 MemoryLeak
3860 Main
通過(guò)命令行打開jconsole
C:\>jconsole 4568
實(shí)現(xiàn)了hasCode和equals的Key類和沒有實(shí)現(xiàn)的圖表如下所示:
沒有內(nèi)存泄露的:
造成內(nèi)存泄露的:
- Java DWR內(nèi)存泄漏問(wèn)題解決方案
- macOS上使用gperftools定位Java內(nèi)存泄漏問(wèn)題及解決方案
- Java內(nèi)存模型可見性問(wèn)題相關(guān)解析
- Java內(nèi)存泄漏問(wèn)題處理方法經(jīng)驗(yàn)總結(jié)
- 解決Java導(dǎo)入excel大量數(shù)據(jù)出現(xiàn)內(nèi)存溢出的問(wèn)題
- 完美解決java讀取大文件內(nèi)存溢出的問(wèn)題
- 詳解Java中synchronized關(guān)鍵字的死鎖和內(nèi)存占用問(wèn)題
- 解析Java的JNI編程中的對(duì)象引用與內(nèi)存泄漏問(wèn)題
- JAVA程序內(nèi)存溢出問(wèn)題原因分析
- 基于Java 數(shù)組內(nèi)存分配的相關(guān)問(wèn)題
- Java 內(nèi)存安全問(wèn)題的注意事項(xiàng)
相關(guān)文章
MyBatis查詢無(wú)記錄時(shí)的返回值問(wèn)題
這篇文章主要介紹了MyBatis查詢無(wú)記錄時(shí)的返回值問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01Java結(jié)構(gòu)型設(shè)計(jì)模式之享元模式示例詳解
享元模式(FlyWeight?Pattern),也叫蠅量模式,運(yùn)用共享技術(shù),有效的支持大量細(xì)粒度的對(duì)象,享元模式就是池技術(shù)的重要實(shí)現(xiàn)方式。本文將通過(guò)示例詳細(xì)講解享元模式,感興趣的可以了解一下2022-09-09關(guān)于SpringBoot整合redis使用Lettuce客戶端超時(shí)問(wèn)題
使用到Lettuce連接redis,一段時(shí)間后不操作,再去操作redis,會(huì)報(bào)連接超時(shí)錯(cuò)誤,在其重連后又可使用,糾結(jié)是什么原因?qū)е碌哪?,下面小編給大家?guī)?lái)了SpringBoot整合redis使用Lettuce客戶端超時(shí)問(wèn)題及解決方案,一起看看吧2021-08-08Java中String的JdbcTemplate連接SQLServer數(shù)據(jù)庫(kù)的方法
這篇文章主要介紹了Java中String的JdbcTemplate連接SQLServer數(shù)據(jù)庫(kù)的方法,在研發(fā)過(guò)程中我們需要與其他系統(tǒng)對(duì)接的場(chǎng)景,連接SQLServer拉取數(shù)據(jù),所以就用jdbc連接數(shù)據(jù)庫(kù)的方式連接外部數(shù)據(jù)源,需要的朋友可以參考下2021-10-10JAVA 根據(jù)身份證計(jì)算年齡的實(shí)現(xiàn)代碼
這篇文章主要介紹了JAVA 根據(jù)身份證計(jì)算年齡的實(shí)例代碼及java根據(jù)出生日期獲得年齡的方法,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05Java使用POI從Excel讀取數(shù)據(jù)并存入數(shù)據(jù)庫(kù)(解決讀取到空行問(wèn)題)
有時(shí)候需要在java中讀取excel文件的內(nèi)容,專業(yè)的方式是使用java POI對(duì)excel進(jìn)行讀取,這篇文章主要給大家介紹了關(guān)于Java使用POI從Excel讀取數(shù)據(jù)并存入數(shù)據(jù)庫(kù),文中介紹的辦法可以解決讀取到空行問(wèn)題,需要的朋友可以參考下2023-12-12MyBatis傳入?yún)?shù)為L(zhǎng)ist對(duì)象的實(shí)現(xiàn)
這篇文章主要介紹了MyBatis傳入?yún)?shù)為L(zhǎng)ist對(duì)象的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03