内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
内存泄漏形象的比喻是"操作系统可提供给所有进程的存储空间正在被某个进程榨干",最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃。所以"内存泄漏"是从操作系统的角度来看的。这里的存储空间并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。由程序申请的一块内存,如果没有任何一个指针指向它,那么这块内存就泄漏了。
while(1){malloc(1024);}这种进程
在Java中内部类的定义与使用一般为成员内部类与匿名内部类,他们的对象都会隐式持有外部类对象的引用,影响外部类对象的回收。
GC只会回收没有被引用或者根集不可到达的对象(取决于GC算法),内部类在生命周期内始终持有外部类的对象的引用,造成外部类的对象始终不满足GC的回收条件,反映在内存上就是内存泄露。(如,Android中Activity的内存泄露)
解决方案为
1.将内部类定义为static
2.用static的变量引用匿名内部类的实例
1.成员内部类
/**
* 成员内部类
*/
public class Outer {
private int outer = 1;
class Inner {
public void show() {
System.out.println("outer =" + outer);
}
}
public static void main(String[] args) {
Outer.Inner in = new Outer().new Inner();
in.show();
}
}
2.方法内部类
/**
* 方法内部类
*
*/
public class Outer2 {
private int outer = 1;
public void showOut() {
class Inner {
public void show() {
System.out.println("outer =" + outer);
}
}
new Inner().show();
}
public static void main(String[] args) {
Outer2 in = new Outer2();
in.showOut();
}
}
防止Handler引起内存泄漏:
方法一:通过程序逻辑进行保护:
(1)在关闭Activity时停掉对应的后台线程。线程停止就相当于切断了Handle和外部链接的线,Activity自然会在合适的时候被回收。
(2)如果Handler是被delay的Message持有了引用,那就使用Handler的removeCallbacks()方法将消息对象从消息队列移除即可。
方法二:将Handler声明为静态类,静态类不持有外部类的对象,所以Activity可以被随意回收。此处使用了弱引用WeakReference,也就是说当在内存不足时,系统会销毁弱/回收引用引用的对象,从而达到优化内存的目的。优化后代码如下:
public abstract class WeakHandler<T> extends Handler {
protected WeakReference<T> reference;
//创建子线程Handler使用的构造器
public WeakHandler(Looper looper, T reference) {
super(looper);
this.reference = new WeakReference<>(reference);
}
//创建主线程Handler使用的构造器
public WeakHandler(T reference) {
this.reference = new WeakReference<>(reference);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
T t = reference.get();
if (t == null)
return;
handleMessage(t, msg);
}
protected abstract void handleMessage(T t, Message message);
}
上述代码,我们使用了泛型,这个泛型就是我们之前说的当前类,同时提供了两种构造器,这样不管我们是创建主线程还是非主线程Handler对象时,都不会造成内存泄漏了。