Java内存泄露知识点

java的内存分配

  • 静态存储区: 编译时已经分配好内存,在程序整个运行期间都存在,主要存放静态数据和常量
  • 栈区:当方法执行时,会在栈区中创建方法内部的局部变量,方法结束后自动释放内存
  • 堆区:通常用来存放new出来的对象,由java垃圾回收器回收

内存泄露分析

永远的singleton
由于单例的静态特性,使得它的生命周期和应用的生命周期一样长。当我们使用单例的时候,要注意它内部持有的引用,如Activity(导致Activity不能被回收)

public class Singleton{
    private static Singleton singleton;
    private Context context;
    
    private Singleton(Context context){
        this.context=context;
    }
    
    public static Singleton getInstance(Context context){
        if(singleton==null){
            singletoon=new Singleton(context);
        }
        return singleton;
    }
}

如果该单例中需要一个Context,那么确保不要持有Activity的引用,可以使用Application提供的Context。

让人心塞的handler
handler一般作为Acvivity的非静态内部类被创建,那么他就持有了Activity的引用,当我们发送一个延迟消息的时候,Message持有hanlder的引用,而handler持有Activity的引用,所以,当我们主动调用finish()方法的时候,Activity并不会被回收。而如果我们在Activity中需要引用外部的非static对象,应该通过弱引用传入。

public class DemoActivity extends Activity{
    private static final class MyHandler extends Handler{
        private final WeakReference mActivity;
        
        public MyHandler(DemoActivity activity){
            this.mActivity=new WeakReference(activity);
        }
        @override
        public void handleMessage(Message msg){
            DemoActivity activity=mActivity.get();
            if(activity!=null){
                //do sonmething
            }
        }
    }
    
    private final MyHandler handler=new MyHandler(this);
}

静态内部类不会持有外部类的引用,推荐使用静态内部类+弱引用,每次使用时注意进行非空判断。

同时,在Activity被销毁时,可以清空MessageQueue中的消息。

匿名内部类/非静态内部类
一般在Activity、Fragment或者View中创建内部类,如果是非静态内部类,则会持有外部类的引用。
而如果这个内部类被异步线程所引用,则很可能导致内存泄露。

public class DemoActivity extends Activity{
    private static TestInnerBad testInnerBad=null;
    
    class TestInnerBad{}
    
    @override
    public void onCreate(Bundle bundle){
        
        if(testInnerBad==null){
            testInnerBad=new TestInnerBad();  //内存泄露
        }
        Runnable r1=new Runnable(){   //可能内存泄露
            @override
            public void run(){
                    
            }
        }
        Runnable r2=new MyRunnable();
    }
    
    private static class MyRunnable implements Runnable{
        @override
        public void run(){}
    }
}

TestInnerBad是DemoActivity的内部类,持有他的引用,而它又被声明为static,那么他的生命周期就和App一样,那么肯定是造成了DemoActivity无法被正确的回收。对静态类的正确处理方法是---单独抽取出来封装成一个单例。

r1是DemoActivity的匿名内部类,他持有DemoActivity的引用,而如果r1被传入到一个异步线程中,则很可能造成内存泄露。

集合对象的清除
如果这个集合是static,那么该集合会一直持有传入对象的引用,一般要在Activity、Fragment被销毁时将集合清空。

你可能感兴趣的:(Java内存泄露知识点)