美文网首页
[安卓开发日记] 内存泄漏

[安卓开发日记] 内存泄漏

作者: chopperhl | 来源:发表于2020-04-02 16:53 被阅读0次

    一、JAVA的四种引用类型

    1.强引用

    Object obj = new Object();
    String str = "Hello";
    

    这类通常的实例化对象

    2.弱引用

    WeakReference 当JVM进行垃圾回收时无论内存是否充足,都会回收被弱引用关联的对象。可用于解决内存泄漏

    3.软引用

    SoftReference 只有当JVM内存不足时才会回收软引用关联的对象

    4.虚引用

    PhantomReference 不影响对象的被垃圾回收的时机

     ReferenceQueue<String> queue = new ReferenceQueue<String>();
     PhantomReference<String> pr = new PhantomReference<String>("Hello" queue);
    

    虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。

    二、Handler导致的内存泄漏

    非静态的Handler内部类,默认会持有外部的Activity引用。

        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_detail);
            handler = new Handler(){
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                }
            };
            Message message = handler.obtainMessage(1);
            message.obj = "Hello";
            handler.sendMessageDelayed(message, 40000);
        }
    
    

    Handler#sendMessageDelayed 方法,会调用Handler.mQueen.enqueueMessage(Message msg, long when)
    将Message 加入 MesssageQueen ,并设置设置message.target = this(Handler对象)
    上诉流程会形成 如下依赖链

    
    Message -> MessageQueen -> Handler -> Activity
    
    MesageQueen->MainLooper(和application生命周期一致)
    
    

    Message 和 MessageQueen 的依赖 Message 被发送时才会解除
    Activity退出后,在Delay时间到达之前,无论发生多少次GC,根据可达性分析,Activity的内存都不应该被释放。

    解决方案
    • 切断Message到Queen 到引用链,即在Activity销毁时调用 handler.removeMessages(1)
    • 将Handler到Activity的引用变为弱应用,即改用静态的Handler子类,传入WeakReference的Activity应用:
        public static class DetailHandler extends Handler {
            private WeakReference<DetailActivity> contextWeakReference;
    
            public DetailHandler(DetailActivity context) {
                this.contextWeakReference = new WeakReference<>(context);
            }
    
            public DetailActivity getContextWeakReference() {
                return contextWeakReference.get();
            }
    
            @Override
            public void handleMessage(@NonNull Message msg) {
                super.handleMessage(msg);
            }
        }
    

    3.静态的实例持有非静态的类(短周期的对象)

    public class AppManager {
        private static AppManager INSTANCE;
        private Context context;
    
        private AppManager(Context context) {
            this.context =  context;
        }
    
        public static AppManager getInstance(Context context) {
            return new AppManager(context);
        }
    
        public void test(){
    
        }
    }
    

    INSTANCE 的生命周期和整个App一致,如果getInstance 传入的Context 为Activty,则Activty会被AppManager一直持有,导致Activity在gc时不能被释放。

    解决方案

    这里传入ApplicationContext这样的长周期对象即可。
    其他类型的引用可以根据实际情况,在适当的时机置空即可。

    相关文章

      网友评论

          本文标题:[安卓开发日记] 内存泄漏

          本文链接:https://www.haomeiwen.com/subject/mzbxphtx.html