JAVA內(nèi)存泄漏
由于JAVA與C++的主要區(qū)別在于薪棒,JAVA存在特有的垃圾回收機(jī)制苇经,JAVA程序員看似不用考慮程序的內(nèi)存使用情況,這種誤解使得JAVA內(nèi)存泄漏的知識點成為面試的核心問題芒帕。而在我之前看過很多技術(shù)類的書中查蓉,大部分書中都將內(nèi)存溢出與內(nèi)存泄漏混為一談赫段,給初學(xué)者帶來了很大的困擾。
目錄
- 內(nèi)存泄漏的兩種情景
- JVM可回收資源的內(nèi)存泄漏
- JVM不可回收資源的內(nèi)存泄漏
1.JVM可回收資源的內(nèi)存泄漏
內(nèi)存泄漏產(chǎn)生的兩個條件:
- 使用數(shù)組(或集合)形式存儲對象
- 數(shù)組(或集合)使用額外的控制變量控制數(shù)組(或集合)的有效區(qū)間
舉例:例如棧矢赁,我們使用數(shù)組a表示棧糯笙,申請了10個大小的空間,我們首先push10次撩银,然后pop9次给涕,這時a中僅僅包含1個元素,如果我們在pop操作中蜒蕾,沒有銷毀數(shù)組中元素所執(zhí)行的內(nèi)存空間稠炬,而僅僅是移動了棧頂指針焕阿,那么a[1]~a[9]元素所指向的內(nèi)存空間由于棧頂指針的限制是訪問不到的咪啡,因而其指向的內(nèi)存空間都應(yīng)該是垃圾,然而在現(xiàn)在的場景下暮屡,這些垃圾仍然有引用指向該內(nèi)存撤摸,這就是內(nèi)存泄漏。
實例程序如下:
package com.feng.fresh.service;
/**
* Created by xinfeng.xu on 2016/11/14.
*/
public class StackDemo {
static final int MAX_SIZE = 10;
static class Student{
public Student(String name, int id) {
this.name = name;
this.id = id;
}
String name;
int id;
}
private Student[] a = new Student[MAX_SIZE];
private int stackTop = 0;
public void push(Student student){
if(stackTop >= MAX_SIZE){
return;
}
a[stackTop++] = student;
}
public Student pop(){
if(stackTop<=0){
return null;
}
return a[--stackTop];
}
public static void main(String[] args) {
StackDemo demo = new StackDemo();
for(int i=0; i<MAX_SIZE; i++){
Student student = new Student(i+"", i);
demo.push(student);
}
for(int i=MAX_SIZE; i>1; i++){
demo.pop();
}
}
}
其內(nèi)存堆棧的分配如下圖所示:
或許會有人提問:
- 如果再次往push元素褒纲,原位置上的元素不就沒有引用而變?yōu)槔藛?/li>
- 如果該類只被用于方法內(nèi)准夷,方法調(diào)用完成之后,整個對象都會成為垃圾
上面兩種說法都是正確的莺掠,但是這只是盡早的覆蓋了內(nèi)存泄漏的問題衫嵌,但我們不能總是保證會push元素或者只是在局部變量使用該對象,內(nèi)存泄漏在該例中是確實存在的彻秆,我們應(yīng)該從程序的角度杜絕內(nèi)存泄漏楔绞。
解決方案,修改StackDemo中的pop方法:
public Student pop(){
if(stackTop<=0){
return null;
}
Student student = a[--stackTop];
a[stackTop] = null;
return student;
}
在pop操作時唇兑,我們應(yīng)該讓數(shù)組中相應(yīng)位置的引用置為null酒朵,當(dāng)進(jìn)行垃圾回收時,JVM就可以回收該資源了扎附,而不會出現(xiàn)不可控的局面蔫耽。
2. JVM不可回收資源的內(nèi)存泄漏
JVM的垃圾回收機(jī)制,只能回收堆中的內(nèi)存留夜,而對于一些資源(例如IO流匙铡,線程資源等等)是不受JVM管理的,因為使用該類資源應(yīng)該手動關(guān)閉碍粥,否則該類資源就會越來越多鳖眼,占用越來越多的資源,最終會導(dǎo)致服務(wù)器癱瘓即纲,引起巨大的損失具帮。