内存泄露:程序在向系统申请分配内存空间后,在使用完毕后未释放。结果导致一直占据该内存单元,我们和程序都无法再使用该内存单元,直到程序结束,这是内存泄露。
内存泄露原因分析
在JAVA中JVM的栈记录了方法的调用,每个线程拥有一个栈。在线程的运行过程当中,执行到一个新的方法调用,就在栈中增加一个内存单元,即帧(frame)。在frame中,保存有该方法调用的参数、局部变量和返回地址。然而JAVA中的局部变量只能是基本类型变量(int),或者对象的引用。所以在栈中只存放基本类型变量和对象的引用。引用的对象保存在堆中。
当某方法运行结束时,该方法对应的frame将会从栈中删除,frame中所有局部变量和参数所占有的空间也随之释放。线程回到原方法继续执行,当所有的栈都清空的时候,程序也就随之运行结束。
而对于堆内存,堆存放着普通变量。在JAVA中堆内存不会随着方法的结束而清空,所以在方法中定义了局部变量,在方法结束后变量依然存活在堆中。
综上所述,栈(stack)可以自行清除不用的内存空间。但是如果我们不停的创建新对象,堆(heap)的内存空间就会被消耗尽。所以JAVA引入了垃圾回收(garbage collection,简称GC)去处理堆内存的回收,但如果对象一直被引用无法被回收,造成内存的浪费,无法再被使用。所以对象无法被GC回收就是造成内存泄露的原因!
内存泄漏:
public class GC {
public static void main(String[] args) {
byte[] a = new byte[1024*1024];
System.gc();
}
}
结果:没有被回收
修改代码后:
public class GC {
public static void main(String[] args) {
{
byte[] a = new byte[1024];
} //局部变量表中的Slot不存在关于a数组对象的引用了。
int b = 10; //a原本所占用的Slot被b变量所复用
//所以此时GC Roots的局部变量与他没有关联了
System.gc();
}
}
结果:被回收
JVM内存泄漏检测,可以通过jdk自带的jvisualvm
VisualVM工具的使用点击链接https://www.cnblogs.com/kongzhongqijing/articles/3625340.html