Java内存泄露系列--内存泄露的原因及解决方案(大全)
原文網址:Java內存泄露系列--內存泄露的原因及解決方案(大全)_IT利刃出鞘的博客-CSDN博客
簡介
簡介
? ? ? ? 本文介紹Java中內存泄露的一些原因與解決方案。
? ? ? ? 如果內存泄露的空間足夠大,就會導致內存溢出(OOM)。
內存泄露的原因
? ? ? ? 堆內存中一個對象不再使用時,垃圾回收器卻無法從內存中刪除他們,導致內存泄露。
內存泄露的影響
- 長時間連續運行時性能嚴重下降;
- 出現OOM導致應用崩潰;
內存泄露的檢測與分析
通常我們可以借助MAT、LeakCanary等工具來檢測應用程序是否存在內存泄漏。
1、MAT是一款強大的內存分析工具,功能繁多而復雜。
2、LeakCanary則是由Square開源的一款輕量級的第三方內存泄漏檢測工具,當檢測到程序中產生內存泄漏時,它將以最直觀的方式告訴我們哪里產生了內存泄漏和導致誰泄漏了而不能被回收。?
內存泄露的類型
主要有以下類型:
ThreadLocal
相關網址
Java的ThreadLocal導致內存泄露----原因/解決方案_IT利刃出鞘的博客-CSDN博客
簡介
? ? ? ? 使用ThreadLocal時,每個線程只要處于存貨狀態就可保留對其ThreadLocal變量副本的隱式調用,且將保留其自己的副本。使用不當,就會引起內存泄露。
? ? ? ? 一旦線程不在存在,ThreadLocals就應該被垃圾收集,而現在線程的創建都是使用線程池,線程池有線程重用的功能,因此線程就不會被垃圾回收器回收。所以使用到ThreadLocals來保留線程池中線程的變量副本時,ThreadLocals沒有顯示的刪除時,就會一直保留在內存中,不會被垃圾回收。
解決方法
static字段
簡介
? ? ? ? 大量使用static字段會潛在的導致內存泄露,在Java中,靜態字段通常擁有與整個應用程序相匹配的生命周期。
? ? ? ? 示例:單例的靜態特性使得其生命周期和應用的生命周期一樣長,如果一個對象已經不再需要使用了,而單例對象還持有該對象的引用,就會使得該對象不能被正常回收,從而導致了內存泄漏。
解決方法
未關閉的資源
簡介
? ? ? ?對于使用了BroadcastReceiver,ContentObserver,File,Cursor,Stream,Bitmap等資源,應該在Activity銷毀時及時關閉或者注銷,否則這些資源將不會被回收,從而造成內存泄漏。
解決方法
調用它的close()函數將其關閉掉,然后再設置為null
注意
集合容器
簡介
? ? ? ? 我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中,如果在不需要該對象時,沒有把對象的引用從集合中清理掉,這樣這個集合就會越來越大。
????????如果這個List是臨時的,那沒問題,List被回收后里邊的對象引用也就不會被持有了(對象不可達),對象引用也會被回收。如果這個List不是臨時的,那么就會導致內存占用越來越大。
? ? ? ? 如果這個集合是static的話,那情況就更嚴重了。如果這些容器為靜態的,那么它們的生命周期與程序一致,則容器中的對象在程序結束之前將不能被釋放,從而造成內存泄漏。簡單而言,長生命周期的對象持有短生命周期對象的引用,盡管短生命周期的對象不再使用,但是因為長生命周期對象持有它的引用而導致不能被回收。
解決方法
改變哈希值
簡介
? ? ? ? 當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的哈希值與最初存儲進HashSet集合中時的哈希值就不同了。在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存泄露
解決方法?
內部類持有外部類
相關網址
Java的內部類持有外部類導致內存泄露--原因/解決方案_IT利刃出鞘的博客-CSDN博客
簡介
? ? ? ? 若一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內部類持有外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄露。
? ? ? ??在Java中,非靜態內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態內部類卻不會。
解決辦法
finalize()方法
簡介
重寫finalize()方法時,該類的對象不會立即被垃圾收集器收集,如果finalize()方法的代碼有問題,那么會潛在的引發OOM;
解決辦法
常量字符串
簡介
? ? ? ? 如果我們讀取一個很大的String對象,并調用了intern(),那么它將放到字符串池中,位于PermGen中,只要應用程序運行,該字符串就會保留,這就會占用內存,可能造成OOM。
解決方法
- 增加PermGen的大小,-XX:MaxPermSize=512m;
- 升級Java版本,JDK1.7后字符串池轉移到了堆中。?
其他網址
8種JVM內存溢出(OOM)的原因和解決方法--掘金
Java中的內存泄露問題 及解決方法_java_多多-CSDN博客
徹底搞懂Java內存泄露 - 簡書
java中內存泄露8種情況的總結_java_ratel的博客-CSDN博客
總結
以上是生活随笔為你收集整理的Java内存泄露系列--内存泄露的原因及解决方案(大全)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python 实现定时任务的八种方案,定
- 下一篇: 数据中心网络规划设计,数据中心设计规范解