Android-内存泄漏处理

  1. 点击Profiler如图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 下面我们手动触发GC来回收无用的内存,如图:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  2. 反复的打开和关闭界面,如果发现App占用的内存只增不减,那么就是发生了内存泄漏。

内存泄漏的发生


之前讲述了如何检测发生了内存泄漏,为进一步观察内存泄漏现象,下面举个例子:

未能移除定时的Runnable任务

通常有需要延时处理时,常常调用Handler对象的postDelayed方法,由该方法延迟一段时间后执行设定好的Runnable任务。若要实现动画效果,则循环执行若干次postDelayed方法。这里蕴含着不晓得内存泄露风险,如不谨慎,App可能多跑几次就挂了。

比如下面的代码每隔两秒打一行日志,并在onDestroy页面退出时根据开关来判断是否移除任务,

代码如下:

public class RemoveTaskActivity extends AppCompatActivity implements OnClickListener{

private CheckBox ck_remove;

private TextView tv_remove;

private Button btn_remove;

private String mDesc=“”;

private boolean isRunning=false; //定时任务是否在运行

private Handler mHandler=new Handler(); //声明一个处理器对象

protected void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_remove_task);

ck_remove=findViewById(R.id.ck_remove);

tv_remove=findViewById(R.id.tv_remove);

btn_remove=findViewById(R.id.btn_remove);

btn_remove.setOnClickListener(this);

TextView tv_start=findViewById(R.id.tv_start);

tv_start.setText(“页面打开的时间为:”+DateUtil.getNowTime());

}

public void onClick(View v)

if(v.getId()==R.id.btn_remove){

if(!isRunning){

btn_remove.setText(“取消定时任务”);

//立即启动定时任务

mHandler.post(mTask);

}else{

btn_remove.setText(“开始定时任务”);

//移除定时任务

mHandler.removeCallbacks(mTask);

}

isRunning=!isRunning;

}

}

protected void onDestroy(){

super.onDestroy();

if(ck_remove.isChecked()){

//移除定时任务

mHandler.removeCallbacks(mTask);

}

}

//定义一个定时任务,用于定时发送广播

private Runnable mTask=new Runnable(){

@Override

public void run{

Intent intent=new Intent(TASK_EVENT);

//通过本地的广播管理器来发送广播

LocalBroadcastManager.getInstance(RemoveTaskActivity.this).sendBroadcast(intent);

//延迟2秒后再次启动定时任务

mHandler.postDelayed(this,2000);

}

};

public void onStart(){

super.onStart();

//创建一个定时任务的广播接收器

taskReceiver=new TaskReceiver();

//创建一个意图过滤器,只处理指定事件来源的广播

IntentFilter filter=new Intentfilter(TASK_EVENT);

//注册广播接收器,注册之后才能正常接受广播

LocalBroadcastManager.getInstance(this).registerReceiver(taskReceiver,filter);

}

public void onStop(){

//注销广播接收器,注销之后就不再接受广播

LocalBroadcastManager.getInstance(this).registerReceiver(taskReceiv
er,filter);

}

//声明一个定时任务广播事件的标识串

private String TASK_EVENT=“com.example.performance.task”;

//声明一个定时任务的广播接收器

private TaskReceiver taskReceiver;

//定义一个广播接收器,用于处理定时任务事件

private class TaskReceiver extends BroadcastReceiver{

//在收到定时任务的广播时触发

public void onReceive(Context contect,Intent intent){

if(intent !=null){

mDesc=String.format(“%s%s 打印了一行测试日志\n”,mDesc,DateUtil.getNowTime());

tv_remove.setText(mDesc);

}

}

}

进入测试页面,点击开始执行任务按钮,页面会每隔2秒打印一行日志。然后不停止也不移除定时任务,直接退出该页面,按道理原测试页面上的内存都应该回收,不过接着进入测试页面,还没点击开始执行任务按钮,页面已经在自己打印日志了,很明显上次退出页面时系统未能自动的回收内存。

内存泄漏的预防


App开发中的内存泄露还常见于以下5个场景:

(1)数据库查询操作后没有关闭游标Cursor。

(2)适配器Adapter刷新数据时没有重用convertView对象。

(3)Bitmap对象使用完毕没有调用recycle方法回收内存。

(4)Activity引用了耗时对象,造成页面关闭时无法释放被引用的对象。

(5)给系统服务注册了监听任务,却没有及时注销。

要想避免出现内存泄漏,最好的办法就是防患于未然。针对以上5个内存泄漏场景,相应的预防措施分别如下:

  1. 关闭游标–游标Cursor不只用于数据库SQLite查询记录,也可用于内容解析器ContentResolver查询内容数据,还可以用于下载管理器DownloadManager查询下载进度。若要预防游标产生的内存泄漏,则可在每次查询操作结束后调用Cursor对象的close方法关闭游标。

  2. 重用适配–App网列表视图ListView或网格视图GirdView中填充数据都是通过适配器BaseAdapter的getView方法展示列表元素。列表元素较多时,系统只会加载屏幕上可见元素,其他元素只有滑动到屏幕区域内才会及时加载并显示。当列表元素多次处于“展示—>隐藏—>展示—>隐藏·····”时,有必要重用每个元素的视图如果不重用,那么每次展示可视元素都得重新分配视图对象,这便产生了内存泄漏。下面是重要列表元素的代码示例:

ViewHolder holder;

if(convertView==null){

holder=new ViewHolder();

convertView=mInflater.inflate(R.layout.list_title,null);

holder.tv_seq=(TextView)convertViewById(R.id.tv_seq);

holder.iv_title=(TextView)convertViewById(R.id.iv_title);

convertView.setTag(holder);

}else{

holder=(ViewHolder)convertView.getTag();

}

  1. 回收图像–若想避免图像操作引起的内存泄漏,可在Bitmap对象使用完毕后调用recycle方法。

  2. 释放引用–下面是预防这种内存泄漏的3个方法:

v_seq);

holder.iv_title=(TextView)convertViewById(R.id.iv_title);

convertView.setTag(holder);

}else{

holder=(ViewHolder)convertView.getTag();

}

  1. 回收图像–若想避免图像操作引起的内存泄漏,可在Bitmap对象使用完毕后调用recycle方法。

  2. 释放引用–下面是预防这种内存泄漏的3个方法:

  • 22
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值