Android 内存泄露与内存溢出

什么是内存泄露(Memory Leak)?


      Android虚拟机的垃圾回收采用的是跟搜索算法。GC会从根节点(GC Roots)开始对heap进行遍历。到最后,部分没有直接或者间接引用到GC Roots的就是需要回收的垃圾,会被GC回收掉。内存泄露是指进程中某些对象(垃圾对象)已经没有使用价值了。但是它们却可以直接或者间接引用到GC Roots导致无法被GC回收。无用的对象占据着内存空间,导致不能及时回收这个对象所占用的内存。当内存泄露累计超过Dalvik堆大小,就会发生内存溢出(OOM out of memory)。


造成内存泄露的两大原因有Activity泄露(Activity Leak)和Bitmap泄露(Bitmap Leak)。


Activity Leak:对activity等组件的引用应该控制在其生命周期之内;如果不能做到就考虑使用get ApplicationContext或者get Application,以避免Activity被外部长生命周期的对象引用而泄露。

比如:单例模式:单例模式情况下,因为单例的静态特性使得其生命周期跟应用的生命周期一样长,所以单例模式若需要Context的话,就使用Application的Context;

public class MyApplication extends Application{

    private Context context;
    private static MyApplication instance;

    private MyApplication(){
        context = getApplicationContext();
    }

    public static MyApplication getInstance(){
        if(instance == null){
            instance = new MyApplication();
        }
        return instance;
    }
}


           非静态内部类:在频繁调用其外类的时候,外类每次都会引用内部类对象,所以将内部类初始化为静态变量,这种情况下虽然不在频繁new 对象,可会导致该外部类的内存资源不能正常被回收。所以这种情况应该将内部类设为静态内部类;

public class MainActivity extends AppCompatActivity {

    private static InnerClass innerClass = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(innerClass == null){
            innerClass = new InnerClass();
            //.....
        }
    }

    private static class InnerClass{
        //.....
    }
}


           匿名内部类:是常用在多线程的实现上,此时外部类的实例是被此内部类持有的,如果有引用的话,异步线程与主线程的生命周期是不同的,就会造成Activity泄露。所以,不要直接引用该主Activity的Context,使用getApplication;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Runnable(){

            @Override
            public void run() {
                ImageView imageView = new ImageView(getApplicationContext());
                //......
            }
        }.run();
    }
}


          Handler造成的内存泄露:

          1.在Activity的onStop或者onDestroy中removeMessage,以保证若Activity finish的时候handler还没有完成操作,则Message及发送它的Handler对象将线程MessageQueue一直持有。由于Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的,就会造成不能正常释放。所以,可以将Handler声明为静态的,若要引用Activity的话,就使用弱引用(Weak Reference)的方式,注意:静态+弱引用时,使用前需判空。


此外,尽量避免使用static成员变量,因为其生命周期与应用的是一样的,假如app具有常驻内存设置,这些变量一直都不会被释放。按照现在手机app内存管理机制,占内存较大的后台进程将优先回收,如果此app做过进程互保保活,那会造成app在后台频繁重启。当手机安装了你参与开发的app以后一夜时间手机被消耗空了电量、流量,你的app不得不被用户卸载或者静默。


Bitmap Leak:如果Bitmap没调用 recycle()方法,当 Bitmap 对象不使用时,我们应该先调用 recycle() 释放内存,然后才它设置为 null. 因为加载 Bitmap 对象的内存空间,一部分是 java 的,一部分C的(因为 Bitmap 分配的底层是通过 JNI 调用的 )。 而这个 recyle() 就是针对 C 部分的内存释放。C,C++ 是需要手动释放内存的。


有参考blog:点击打开链接


什么是内存溢出(out of memory)?

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,就会出现out of memory。


memory leak会最终会导致out of memory!




猜你喜欢

转载自blog.csdn.net/duanmulirui/article/details/67632638
今日推荐