大家推荐个靠谱的公众号程序员探索之路,大家一起加油
从obj=null谈谈java的内存泄漏
问题从何而来:
稍微了解jvm知识或者jvm书籍大部分会看到一条建议:
当你不使用对象的时候这样写
Object a = new Object();
//do something
a=null
这样写其实和c/c++最后释放对象(delete/free)的风格是一样的
那么a=null这样写真的会避免内存泄漏吗?
其实是不会的,这样做能保证的是尽快消除a和实例的关联
那么什么时候对象内存会被释放掉呢?
当没有和实例能够直达的链路时,实例才有可能会被清除掉
这样做得缺点:
这么做明显会降低代码的清晰度以及增加编码的负担,然而所换来的好处,却只是为了避免那根本不一定存在的内存泄露。
什么是内存泄漏?
内存泄漏指的是程序在申请内存之后,没有办法释放发掉已经申请到的内存,他始终占用着内存,即被分配的对象可达但无用。内存泄漏一般都是因为内存中有一块很大的对象,但是无法释放。
举个例子:
import java.util.Arrays;
public class TestStack {
private static final int INIT_SIZE = 10;
private Object[] datas;
//记录栈中数据的多少 也就是栈长度
private int size;
public Stack() {
super();
datas = new Object[INIT_SIZE];
}
public void push(Object data){
if (size == datas.length) {
extend();
}
datas[size++] = data;
}
public Object pop(){
if (size == 0) {
throw new IndexOutOfBoundsException("size is zero");
}
return datas[--size];
}
private void extend(){
datas = Arrays.copyOf(datas, 2 * size + 1);
}
}
这是一个简单的可扩展长度的栈
假设业务需求这个栈存储了100万个对象,那么当你pop(出栈)时对象和实例之间是否已经断了联系发现没有,这样就会造成一个现象内存泄漏,对于这种情景就是说对象出栈了但是栈中并没有从内存的角度移除它。
是不是想到java提供的集合框架是怎么处理出集合的操作呢我们来看下(以arraylist为例)
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
哈哈也是=null,看看人家的注释 让gc去工作 但是不是强制性的
其实当TestStack实例被会收时datas数组就会被回收了,也就掩盖了内存泄漏的问题
什么是内存溢出
内存溢出指的是程序在申请内存的时候,没有足够大的空间可以分配了
结论
从定义上可以看出,内存泄漏终将导致内存溢出
注意:定位虚拟机内存问题时,第一步就是要判断到底是内存溢出还是内存泄漏;内存溢出好判断跟踪堆栈信息就可以了。内存泄漏复杂一点,一般都是老年代中的大对象没有释放掉,用通过各种办法找出老年代中的对象没有释放掉的原因。
真正能够解决问题的办法,就是掌握好GC的策略与原理,定义一个变量时多注意变量的作用域,这样才可以更好的避免内存泄露。