第十一章--浅谈android内存和内存泄漏

来源:互联网 发布:广州沙河网络批发 编辑:程序博客网 时间:2024/05/21 17:30

什么是内存

在Android中,通常我们说的内存就是指RAM(随机存取存储器),可以读出读写或者改写,它包括寄存器,栈,堆,静态存储区域,常量池。而且当断电的时候,内存里的东西就销毁了不会保留下来。

垃圾回收

我们知道,java本身就有垃圾回收机制,当我们通过new出一个对象的时候,java虚拟机会为对象分配内存,内存的释放是由垃圾收集器(GC)来回收的,这样做的好处就是可以让开发者专注于功能和业务逻辑的开发,也更加的高效。然而这样也有一些弊端比如会占用大量的资源,由于人为不可控,所以难免会存在部分对象忘记垃圾回收的现象发生,这就是造成内存泄漏的原因。首先说一下java虚拟机的垃圾回收(GC)。

这里写图片描述

他把对象分为Young Generation(年轻代)、Old Generation(老年代)、Permanent Generation(持久代)

  • Young Generation:年轻代又被分为三个区,一个eden区,两个Survivor区,一般程序中生成的大部分对象都在Eden区,当Eden区满了之后,会执行垃圾回收,把还存活的对象转移到第一个Survivor区(S0)。同时如果S0满了之后,垃圾回收也检查在S0存活下来的对象,并转移到第二个Survivor区(S1)
  • Old Generation:存放的是长期存活的对象,或者经过多次GC之后依然活下来的对象
  • Permanent Generation:用于存放静态的类和方法,常量,属性和方法信息

虽然有很多不同的垃圾回收的策略,但通常我们不去关心垃圾回收所用的时间,因为一般垃圾回收所用的时间都是很短的,而是关心其产生的不好的影响,比如Android系统每隔16ms会发出一个触发对UI进行渲染,当帧率大于60FPS,或者这个渲染过程如果保证在16ms以内就能达到一个流畅的画面,然而如果UI渲染过程发生GC,导致绘制时间超过16ms,,就会让用户发送卡顿,应用在手机上的寿命就不长了。。。

内存泄漏

上面已经提到,本来可以回收了然而没有及时回收就会导致内存泄漏的问题,一般有以下5种情况:

  • 单例模式:
public class AppManager {    private static AppManager instance;    private Context context;    private AppManager(Context context) {        this.context = context;    }    public static AppManager getInstance(Context context) {        if (instance != null) {            instance = new AppManager(context);        }        return instance;    }}

一般上面都会传入Activity的上下文,然而单例的周期应该是和应用的一样,所以如果Activity销毁的时候,由于单例持有Activity的引用,所以Activity的内存不会被回收,这就导致了内存泄漏,所以可以把Context改成Application的上下文,这样Application结束的时候,单例也销毁了:

    private AppManager(Context context) {        this.context = context.getApplicationContext();    }
  • 非静态内部类的静态实例造成的泄漏
public class MainActivity extends AppCompatActivity {    private static TestResource mResource = null;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if(mManager == null){            mManager = new TestResource();        }        //...    }    class TestResource {        //...    }}

一般来说非静态内部类会默认持有外部类的引用,而这个内部类又创建了一个一个静态实例,导致这个实例和应用的周期一样长,所以当Activity销毁的时候又不能释放内存,所以也会造成内存泄漏。修改的方法就是将该内部类设为静态内部类或将该内部类抽取出来封装成一个单例,如果需要使用Context,请使用Application的Context 。

  • 还有一个比较常见的就是Handler引起的内存泄漏
public class MainActivity extends AppCompatActivity {    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            //...        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        loadData();    }    private void loadData(){        //...request        Message message = Message.obtain();        mHandler.sendMessage(message);    }}

mHandler作为Handler的非静态内部类的实例,默认持有外部类Activity的引用,消息队列是在一个Looper线程中不断轮询处理消息,那么当这个Activity退出时消息队列中还有未处理的消息或者正在处理消息,而消息队列中的Message持有mHandler实例的引用,mHandler又持有Activity的引用,所以导致该Activity的内存资源无法及时回收,引发内存泄漏。解决方法就是使用静态类并实现Hanlder对Activity的弱引用:

    private static class MyHandler extends Handler {        private WeakReference<Context> reference;        public MyHandler(Context context) {            reference = new WeakReference<>(context);        }        @Override        public void handleMessage(Message msg) {            //...        }    }
  • 线程造成的内存泄漏,基本我们习惯于这样写:
        new Thread(new Runnable() {            @Override            public void run() {                SystemClock.sleep(10000);            }        }).start();

原因和第二个差不多,Activity销毁的时候,线程可能还没有结束,此时Activity便不能被回收。解决方法,改成静态内部类。

  • 资源未关闭造成的内存泄漏
    比如使用的Cursor,BraodcastReceiver等在Activity销毁的时候没有及时关闭或者注销,也会造成内存泄漏的问题。

以上就是平时会遇到的内存泄漏的问题。

内存检测工具

android studio 为我们提供了一些检测内存的工具,具体使用见另外一篇文章。

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 百家号申请过新手被拒绝三次怎么办 6岁儿童个子高不长肉体形瘦怎么办 网页游戏加载完毕卡了不动怎么办 小番茄未成熟下面就坏掉是怎么办 千牛快捷短语界面变得好宽怎么办 申请大王卡手机号填错了怎么办 别人盗用我手机号申请微信号怎么办 淘宝支付宝里没钱了买家退款怎么办 如果外包把员工社保忘交了怎么办 外包工人没有和包工头的证据怎么办 试用期辞职公司给交的社保怎么办 单位给交员工不想交社保怎么办 淘宝收不到卖家的信息怎么办 不小心把微信聊天记录删掉了怎么办 不小心把打印机驱动删除了怎么办 蓝牙不小心点到忽略此设备怎么办 千牛工作台无线开店确认不了怎么办 开通诚信通后营业执照注销了怎么办 淘宝标的货跟发的不一样怎么办 wps表格里单元之间重叠了怎么办 淘宝店铺停了一段时间没了怎么办 转转买家收货为敲诈卖家怎么办 淘宝被投诉盗用官网图片怎么办 淘宝订单买下后卖家告知无货怎么办 盗图被删除还是待处理违规该怎么办 如果买家说你们的买家秀一样怎么办 花呗唤起安全核身验证失败怎么办 淘宝买东西花呗分期额度不够怎么办 支付宝余额支付额度已达上限怎么办 我是淘宝卖家遇到无良买家怎么办 我的保证金被淘宝当做违约金怎么办 淘宝顾客不想退货申请仅退款怎么办 被买家提供证明说我卖假货怎么办 淘宝退货快递公司填错了俩次怎么办 淘宝上退货把运单号写错了怎么办? 阿里巴巴发货了快递单号掉了怎么办 淘宝上买东西货物被物流扣留怎么办 淘宝买错了对方已发货怎么办 淘宝卖家发货的时候没货了怎么办 买了球显示未出票中奖了怎么办 点错了允许易企秀获得权限怎么办