概述
注意是内存泄露,不是内存溢出。啊
首先先看一下下面这样一段代码
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
SystemClock.sleep(1000);
}
}
}).start();
}
Thread 是一个匿名内部类,,当我们finish的时候,该activity实例不会真正销毁,GC机制也不会进行该实例的垃圾回收,因为匿名内部类和非静态内部类持有外部类的强引用,也就是说Thread持有外部activity的强引用,而thread内部while(true)是死循环,线程不会停止,对外部activity的强引用也不会消失。这样就造成了 memory leak,内存溢出。通常情况下我们可以设置一个flag,在activity,的生命周期ondestroy中改变flag的状态,但是!!!主线程和子线程的执行时有线程调度的,也就是说会造成竞争的现象,两个线程会争夺cup时间片的执行权,额。。越挖越深,这又会造成我们虽然改变的flag的状态,但是,子线程中的flag并不是马上就能改变值,因为jvm memory model,原型和执行原理,所有的线程都是在自己的工作内存中工作的,对值得操作是先从主内存读取到工作线程的工作内存中,然后cpu对工作内存的值进行修改,最后再写回主内存,所以主线程对flag的操作可能恰好的发生在子线程已经读完主内存的值到工作内存,但是还没有执行的这段时间,所以,我们应该让flag的状态改变能够让子线程马上可见,应该在声明flag的时候加上volatile关键字,虽然该关键字不能保证操作的原子性,但是能够保证变量flag的可见性。当然,还有,我们可以声明一个静态类。但是!!!慎用静态类与静态变量,比如当我们旋转屏幕,可能会造成activity的销毁与重建(虽然国内很多应用不允许旋转屏幕),不希望重新加载图片,所以,有些人会这样写:private static Drawable background;然后,这样:ImageView imageView = new ImageView(MainActivity.this);
imageView.setBackground(background);很聪明,这样无论旋转多少次屏幕,bitmap都不会重新加载了,省去了大量的时间,但是!!!imageView 引用了MainActivity的context。imageView.setBackground(background);这句源码中(父类View中)background.setCallback(this);background又引用了imageView的回调强引用,这样旋转屏幕,就会造成之前的MainActivity不能被销毁和回收,他的生命甚至和static一样长,所以,内存泄露了。记得Android官方博有个经典的例子和这个很像。当然,还有很多情况会造成内存泄露,譬如,我们经常这样声明一个匿名内部handler:private Handler handler = newHandler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};和匿名内部线程thread一样,会造成内部泄露的隐患。
最后
以上就是玩命魔镜为你收集整理的关于匿名内部类,非静态内部类会造成内存泄露的隐患。的全部内容,希望文章能够帮你解决关于匿名内部类,非静态内部类会造成内存泄露的隐患。所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复