安卓优化二(内存泄漏的处理)

内存泄漏处理

1. 内存泄漏的检测和产生

Java设计之初已近实现了多数情况的内存自动回收,不过在Android开发中,内存回收机制并不总会奏效。

  • 调用了非Java接口,比如调用了JNI接口,JNI代码中由C/C++分配的内存就要手工回收。
  • 调用了外部服务,使用完毕就得手工通知外部服务回收。
  • 异步处理,实时内存回收机制难以回收耗时较久的异步处理任务。

正常情况下,一个App占用的内存有一个峰值,达到这个峰值后,只要退出App页面,占用的内存也会降下来。如果发生了内存泄漏,这个App占用的内存大小是没有峰值的,当该页面重复打开或者随着时间增长,该App消耗的内存越变越大,这便是表现内存泄漏状况。
为了检测内存泄漏,Android Studio自带简单的内存检测工具。使用如下图所示。
在这里插入图片描述

2.内存泄漏预防

App开发中的的5个常见内存泄漏的场景:
1.数据库查询操作后没有关闭游标Cursor。
要预防游标产生的内存泄漏,则可以在每次查询操作结束后调用Cursor对象的close方法关闭游标。
2.适配器Adapter刷新数据时没有重用convertView对象。
App列表视图ListView或者网格视图GridView中填充数据都是通过适配器BaseAdapter的getView方法展示列表元素。当列表元素较多时,系统只会加载屏幕上的可见元素,其它元素只用滑动到屏幕区域才会即使加载并显示。当列表元素多次处于“展示到隐藏”时,有必要重用每个元素的视图,如果不重用,那么每次展示可视元素都得重新分配视图对象,这便产生了内存泄漏。
重用适配可先判断convertView对象,如果该对象为空,就为其分配视图对象,并调用setTag()保存视图持有者;如果该对象非空,就调用getTag()获取视图持有者。下面是重用列表元素的代码

ViewHolder holder=null;
if(convertView==null){
       holder=new ViewHolder();
       convertView=mInflate.inflate(R.layout.list_title,null);
       holder.tv_saq=(TextView)convertView.findViewByld(R.id.tv_seq);
       holder.iv_saq=(Image)convertView.findViewByld(R.di.iv_seq);
       convertView.setTag(holder);
       }else{
            holder=(ViewHolder)convertView.getTag();
            }
      

为了减少ListView和GridView构造适配器都要加入上述代码,可使用RecyclerView,它的适配器自动实现视图持有者ViewHolder,无需判断处理。
Ps:如果代码量不大,可以继续使用ListView,比RecyclerView方便。
3.Bitmap对象使用完毕没有调用recycle方法回收内存。
在Android里Bitmap类中,读取图像数据的底层操作并非由Java代码完成。在SDK源码中,会发现nativeDecodeStream函数,发现它其实是一个native方法,也就是该方法来自JNI接口。需要手动释放C/C++的内存资源。
在Bitmap类的源码,它的回收方法recycle用到的nativeRecycle函数其实也是一个native方法,同样也是JNI接口。
所以为了避免图像操作引起的内存泄漏,可在Bitmap对象使用完毕后调用recycle方法。
4.Activity引用了耗时对象,造成页面关闭是无法释放被引用的对象。
下面是预防这种内存泄漏的三个方法:

  • 如果异步任务是由Handler对象的postDelayed方法发起的,那么可用对应的removeCallbacks方法回收,把消息对象从消息队列移除就行。
  • 把Handler类改位静态类,同时Handler内部使用weakReference关键字持有的目标引用。

可以了解一下jvm的四种引用:强引用 Strong Reference、软引用 Soft Reference弱引用 WeakReference、虚引用 PhantomReference

使用静态类不持有目标引用,不会影响内存自动回收机制,使用弱引用之前,先判断对象是否为空,下面是弱引用代码片段:

private static class MyHandler extends Handler{
        public static weakReference<HandlerActivity> mAcitity;
        public MyHandler(HandlerActivity activity){
                 mActivity = new WeakReference<HandlerActivity>(activity);
           }      
            @Override
            public void handleMessage(Message msg){
                      HandlerActivity act = mActivty.get();
                      if(act!=null){
                         String desc=ProcessUtil.getRunningAppProcessInfo(this);
                         act.tv_memory.setText(desc);
                         }
                  }
              }           
  • 把Handler对象作为App的全局变量,就是把Handler对象作为自定义Application类的成员,App在运行是,对象就一直存在。避免了Handler对象被重复分配内存。

5.给系统服务注册了监听任务,却没即使注销。
一定确保onDestory方法中已经包含相关的注销代码。
常见系统服务拥有不同的注销方法

系统服务的管理器注销函数
AlarmManagercancel
ConnectivityManagerunregisterNetworkCallback
NotificationManagercancel
LocationManagerremove
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值