概述
內(nèi)存泄漏指你用malloc或new申請了一塊內(nèi)存,但是沒有通過free或delete將內(nèi)存釋放,,導(dǎo)致這塊內(nèi)存一直處于占用狀態(tài)
內(nèi)存溢出指你申請了10個字節(jié)的空間,,但是你在這個空間寫入11或以上字節(jié)的數(shù)據(jù),就是溢出
要點
1,、內(nèi)存泄露是指程序中間動態(tài)分配了內(nèi)存,,但在程序結(jié)束時沒有釋放這部分內(nèi)存,從而造成那部分內(nèi)存不可用的情況,,重啟計算機可以解決,,但也有可能再次發(fā)生內(nèi)存泄露,內(nèi)存泄露和硬件沒有關(guān)系,,它是由軟件設(shè)計缺陷引起的。
2,、內(nèi)存泄漏可以分為4類:
1)常發(fā)性內(nèi)存泄漏,。發(fā)生內(nèi)存泄漏的代碼會被多次執(zhí)行到,每次被執(zhí)行的時候都會導(dǎo)致一塊內(nèi)存泄漏,。
2)偶發(fā)性內(nèi)存泄漏,。發(fā)生內(nèi)存泄漏的代碼只有在某些特定環(huán)境或操作過程下才會發(fā)生。常發(fā)性和偶發(fā)性是相對的,。對于特定的環(huán)境,,偶發(fā)性的也許就變成了常發(fā)性的。所以測試環(huán)境和測試方法對檢測內(nèi)存泄漏至關(guān)重要,。
3)一次性內(nèi)存泄漏,。發(fā)生內(nèi)存泄漏的代碼只會被執(zhí)行一次,或者由于算法上的缺陷,,導(dǎo)致總會有一塊僅且一塊內(nèi)存發(fā)生泄漏,。比如,,在類的構(gòu)造函數(shù)中分配內(nèi)存,在析構(gòu)函數(shù)中卻沒有釋放該內(nèi)存,,所以內(nèi)存泄漏只會發(fā)生一次,。
4)隱式內(nèi)存泄漏。程序在運行過程中不停的分配內(nèi)存,,但是直到結(jié)束的時候才釋放內(nèi)存,。嚴格的說這里并沒有發(fā)生內(nèi)存泄漏,因為最終程序釋放了所有申請的內(nèi)存,。但是對于一個服務(wù)器程序,,需要運行幾天,幾周甚至幾個月,,不及時釋放內(nèi)存也可能導(dǎo)致最終耗盡系統(tǒng)的所有內(nèi)存,。所以,我們稱這類內(nèi)存泄漏為隱式內(nèi)存泄漏,。
3,、內(nèi)存溢出即用戶在對其數(shù)據(jù)緩沖區(qū)操作時,超過了其緩沖區(qū)的邊界,;尤其是對緩沖區(qū)寫操作時,,緩沖區(qū)的溢出很可能導(dǎo)致程序的異常。
4,、內(nèi)存溢出類型:
1)java.lang.OutOfMemoryError:PermGen
space
PermGen space 的全稱是Permanent Generation space,是指內(nèi)存的永久保存區(qū)域,。這塊內(nèi)存主要是被JVM存放Class和Meta信息的,Class在被Loader時就會被放到PermGenspace中,,它和存放類實例(Instance)的Heap區(qū)域不同,,GC不會在主程序運行期對PermGenspace進行清理。
JVM由XX:PermSize設(shè)置非堆內(nèi)存初始值,,默認是物理內(nèi)存的1/64,;
JVM由XX:MaxPermSize設(shè)置最大非堆內(nèi)存的大小,默認是物理內(nèi)存的1/4,。
該錯誤常見場合:
a) 應(yīng)用中有很多Class,,web服務(wù)器對JSP進行pre
compile時。
b) Webapp下用了大量的第三方j(luò)ar, 其大小超過了JVM默認的大小(4M)時,。
2)java.lang.OutOfMemoryError:Java
heap space
在JVM中如果98%的時間是用于GC且可用的Heap
size 不足2%的時候?qū)伋龃水惓P畔ⅰ?/span>
JVM初始分配的內(nèi)存由-Xms指定,,默認是物理內(nèi)存的1/64;
JVM最大分配的內(nèi)存由-Xmx指定,,默認是物理內(nèi)存的1/4,。
JVM內(nèi)存的最大值跟操作系統(tǒng)有很大的關(guān)系。32位處理器雖然可控內(nèi)存空間有4GB,,但是具體的操作系統(tǒng)會給一個限制,,這個限制一般是2GB-3GB(一般來說Windows系統(tǒng)下為1.5G-2G,,Linux系統(tǒng)下為2G-3G),而64bit以上的處理器就不會有限制了,。
注意:如果Xms超過了Xmx值,,或者堆最大值和非堆最大值的總和超過了物理內(nèi)存或者操作系統(tǒng)的最大限制都會引起服務(wù)器啟動不起來。
該錯誤常見場合:
a) Web上傳文件時,。
b) 開啟大型文件或從數(shù)據(jù)庫中一次取了太多的數(shù)據(jù),。
相關(guān)問題
1. Java中會存在內(nèi)存泄漏嗎?
Java中也存在內(nèi)存泄露,。當被分配的對象可達但已無用(未對作廢數(shù)據(jù)內(nèi)存單元的引用置null)即會引起,。
Vector v=new
Vector(10);
for (int i=1;i<100;
i) {
Object o=new
Object();
v.add(o);
o=null;
}
// 此時,所有的Object對象都沒有被釋放,,因為變量v引用這些對象,。
// 對象加入到Vector后,還必須從Vector中刪除,,最簡單釋放方法就是將Vector對象設(shè)置為null,。
2. 內(nèi)存泄露、溢出的異同,?
同:都會導(dǎo)致應(yīng)用程序運行出現(xiàn)問題,,性能下降或掛起。
異:
1) 內(nèi)存泄露是導(dǎo)致內(nèi)存溢出的原因之一,;內(nèi)存泄露積累起來將導(dǎo)致內(nèi)存溢出,。
2) 內(nèi)存泄露可以通過完善代碼來避免;內(nèi)存溢出可以通過調(diào)整配置來減少發(fā)生頻率,,但無法徹底避免,。
3. 如何檢測內(nèi)存泄露?
可以通過一些性能監(jiān)測分析工具,,如 JProfiler,、OptimizeitProfiler。
4. 如何避免內(nèi)存泄露,、溢出,?
1)盡早釋放無用對象的引用,。
好的辦法是使用臨時變量的時候,,讓引用變量在退出活動域后自動設(shè)置為null,暗示垃圾收集器來收集該對象,,防止發(fā)生內(nèi)存泄露,。
2)程序進行字符串處理時,盡量避免使用String,,而應(yīng)使用StringBuffer,。
因為每一個String對象都會獨立占用內(nèi)存一塊區(qū)域,,如:
String str =
"aaa";
String str2 =
"bbb";
String str3 = str str2;
// 假如執(zhí)行此次之后str , str2再不被調(diào)用,那么它們就會在內(nèi)存中等待GC回收,;
// 假如程序中存在過多的類似情況就會出現(xiàn)內(nèi)存錯誤,;
3) 盡量少用靜態(tài)變量。
因為靜態(tài)變量是全局的,,GC不會回收,。
4)避免集中創(chuàng)建對象尤其是大對象,如果可以的話盡量使用流操作,。
JVM會突然需要大量內(nèi)存,,這時會觸發(fā)GC優(yōu)化系統(tǒng)內(nèi)存環(huán)境; 一個案例如下:
// 使用jspsmartUpload作文件上傳,,運行過程中經(jīng)常出現(xiàn)java.outofMemoryError的錯誤,,
// 檢查之后發(fā)現(xiàn)問題:組件里的代碼
m_totalBytes =
m_request.getContentLength();
m_binArray = new byte[m_totalBytes];
// totalBytes這個變量得到的數(shù)極大,導(dǎo)致該數(shù)組分配了很多內(nèi)存空間,,而且該數(shù)組不能及時釋放,。
// 解決辦法只能換一種更合適的辦法,至少是不會引發(fā)outofMemoryError的方式解決,。
5)盡量運用對象池技術(shù)以提高系統(tǒng)性能,。
生命周期長的對象擁有生命周期短的對象時容易引發(fā)內(nèi)存泄漏,例如大集合對象擁有大數(shù)據(jù)量的業(yè)務(wù)對象的時候,,可以考慮分塊進行處理,,然后解決一塊釋放一塊的策略。
6)不要在經(jīng)常調(diào)用的方法中創(chuàng)建對象,,尤其是忌諱在循環(huán)中創(chuàng)建對象,。
可以適當?shù)氖褂胔ashtable,vector創(chuàng)建一組對象容器,,然后從容器中去取那些對象,,而不用每次new之后又丟棄。
7) 優(yōu)化配置,。
5. 內(nèi)存溢出的解決方案,?
一是從代碼層面進行優(yōu)化完善,盡量避免該情況發(fā)生,;
二是調(diào)整優(yōu)化服務(wù)器配置:
1) 設(shè)置-Xms,、-Xmx相等;
2) 設(shè)置NewSize,、MaxNewSize相等,;
3) 設(shè)置Heap
size, PermGen space:
Tomcat 的配置示例:修改 %TOMCAT_HOME%/bin/catalina.bat or catalina.sh
在“echo "Using
CATALINA_BASE: $CATALINA_BASE"”上面加入以下行:
set JAVA_OPTS=-Xms2048m
-Xmx2048m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m