Android内存泄漏(二):匿名类

2017-03-22  本文已影响1032人  meixinxicun

上一节已经介绍了内存泄漏与引用的关系,那么这一节强化一下,看看匿名类跟内存泄漏和引用又存在着什么样的关系呢。

匿名类定义

在实际的项目中看到一个很奇怪的现象,Java可以直接new一个接口,然后在new里面粗暴的加入实现代码,向下面这样:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println(this.getClass());
    }
};
runnable.run();

匿名类相当于在定义类的同时再新建这个类的实例

知识点

匿名类也持有着外部类的强引用。

案例1_匿名AsyncTsk

当你在Activity中定义了匿名的AsyncTsk,当异步任务在后台执行耗时任务期间,Activity不幸被销毁了(用户退出,系统回收),这个被AsyncTask持有的Activity实例就不会被垃圾回收器回收,直到异步任务结束。
我们来看如下代码:

//创建匿名类
void startAsyncTask() {
    new AsyncTask<Void, Void, Void>() {
        @Override protected Void doInBackground(Void... params) {
            while(true);
        }
    }.execute();
}
//匿名类使用
button.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        startAsyncTask();
    }
});

如上代码中匿名类AsyncTask执行期间,所有持有的引用Activity被销毁,那么这个activity实例就无法被垃圾回收器回收,直到异步任务结束。

案例2_匿名Handler

同样道理,定义匿名的Runnable,用匿名类Handler执行。Runnable内部类会持有外部类的隐式强引用,被传递到Handler的消息队列MessageQueue中,在Message消息没有被处理之前,Activity实例不会被销毁了,于是导致内存泄漏。

//创建匿名类
void createHandler() {
    new Handler() {
        @Override public void handleMessage(Message message) {
            super.handleMessage(message);
        }
    }.postDelayed(new Runnable() {
        @Override public void run() {
            while(true);
        }
    }, Long.MAX_VALUE >> 1);
}

//匿名类使用
button.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        createHandler();
    }
});

案例3_匿名Thread

定义匿名的Thread未结束之前,Activity实例不会被销毁,也会导致内存泄漏。

//创建匿名类
void spawnThread() {
    new Thread() {
        @Override public void run() {
            while(true);
        }
    }.start();
}

//匿名类使用
button.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        spawnThread();
    }
});

案例4_匿名TimerTask

定义匿名的TimerTask未结束之前,Activity实例不会被销毁,也会导致内存泄漏。

//创建匿名类
void scheduleTimer() {
    new Timer().schedule(new TimerTask() {
        @Override
        public void run() {
            while(true);
        }
    }, Long.MAX_VALUE >> 1);
}

//匿名类使用
button.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) {
        scheduleTimer();
    }
});

总结

看了上面4个例子,我们来总结一下:只要是匿名类的实例,不管是不是在工作线程中,都会持有外部类(Activity)的强引用,导致内存泄漏。

上一节:Android内存泄漏(一):引用
下一节:Android内存泄漏(三):单例

上一篇 下一篇

猜你喜欢

热点阅读