android中常见的内存泄漏和解决的方法

news/2024/7/7 19:51:05

android中的内存溢出预计大多数人在写代码的时候都出现过,事实上突然认为工作一年和工作三年的差别是什么呢。事实上干的工作或许都一样,产品汪看到的结果也都一样,那差别就是速度和质量了。

写在前面的一点儿想法:工作做完了事实上不会的还有非常多,每天都有莫名的危机感,从真正写代码的这一年多总认为自己的学习速度比别人的慢非常多

内存泄漏是什么鬼?

  • 当某些对象不再被程序所使用。可是这些对象仍然被某些对象所引用着。进而导致垃圾收集器不能及时释放它们。


    (无效的对象没有及时回收。导致内存不够用。致使程序
    出错)
    来个图片了解一下
    这里写图片描写叙述

    知道为什么导致内存泄露那就非常好办了。都是跟对象有关系(就是new出来的 不要想着他会跟你结婚)

主要有以下几方面吧:平时注意一下 全然能够杜绝的

  • Context
  • 内部类(handler等)
  • Cursor
  • Adapter
  • Bitmap

Context的溢出

来个图让大家分分钟理解一下:
这里写图片描写叙述

看到这个图在稍加思索会不会认为我们的工具类 貌似好多都持有了activity,并且工具类还是static类型。
在细琢磨一下呢。是不是activity的上下文都能够被application替代呢?

经验之谈:dialog ,fragment。inflate和启动activity 的上下文都是activity的。其它的都都能够被application替代。比方数据库的 服务的 广播的。都不要再用activity了吧。

当然也要酌情处理。

  • 举个栗子(太多了根本举只是来)

1.获取系统的服务

getSystemService(Context.SENSOR_SERVICE);改为            getApplicationContext().getSystemService(Context.SENSOR_SERVICE);

2.弄个数据库


public class NoteSQLiteOpenHelper extends SQLiteOpenHelper {/*** @param context       上下文 ;* @param name          数据库的名称* @param cursorfactory 游标工厂null为默认的。是从第一条開始查询* @param version       数据库的版本从1開始。

*/

public NoteSQLiteOpenHelper(getApplicationContext()) { super(getApplicationContext(), "note123.db", null, 1); } } 事实上这里用activity的也无所谓可是会出现用着用着就把他弄成静态的了。那就悲剧了。

其它的就是 千万不要在 static的工具类里面 增加activity上下文

内部类的种种问题(感觉这个比較多一些呢)

这里写图片描写叙述

简单说一下呢:比方 activity 开线程 跳刀handler 弹出dialog。 activity在销毁了,thread持有activity。然后跳到了handler,handler的对象也存在着了对吧,然后弹出dialog。这个时候呢dialog也持有了activity。可是由于activity销毁了所以不弹了。但对象还是持有者了。

怎么解决 内部类的问题呢。就是在 依附于的那个类销毁的时候 自己也销毁。

就相似于activity销毁了。什么thread,dialog。handler全关掉

  • handler的情况
public class LeakActivity extends Activity {/*** 声明静态内部类不会持有外部类的隐式引用*/private static class MyHandler extends Handler {private final WeakReference<SampleActivity> mActivity;public MyHandler(SampleActivity activity) {mActivity = new WeakReference<SampleActivity>(activity);}@Overridepublic void handleMessage(Message msg) {SampleActivity activity = mActivity.get();if (activity != null) {// ...}}}private final MyHandler mHandler = new MyHandler(this);/*** 这里的Runnable也是 * 声明静态内部类不会持有外部类的隐式引用*/private static final Runnable sRunnable = new Runnable() {@Overridepublic void run() { /* ... */ }};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);//10分钟之后发送消息 mHandler.postDelayed(sRunnable, 1000 * 60 * 10);// 退回到上一个Activityfinish();}
}@Override
public void onDestroy() {//简单粗暴mHandler.removeMessages(message);mHandler.removeCallbacks(Runnable);mHandler.removeCallbacksAndMessages(null);
}

切断联系即可啦。
- dialog
刚才说的按个 activity都销毁了。

可是还要在handler中运行dialog。那么久做个推断吧

Handler handler = new Handler() {public void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case 1:if (!isFinishing()) {dialog.show();}  break;default:break;}  }  
};
  • thread 和asynctask的情况
    在写这个的时候我就在想我还有必要写么。

    我都已经太久远的没用这两个了。

    我都用的是线程池了。
    以下贴一个自己定义的线程池代码。读者直接拿走(能够用 线程池+handler 或者 线程池+eventbus,rxbus等等来更新ui),activity销毁的事后 直接让线程池关闭即可啦

package com.ihealth.utils;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.TimeUnit;/*** @author wanghao* * 说明:一个简易的线程池管理类。提供三个线程池 进本的 子线程操作都能够满足* * 线程内部都是 挨个进行,仅仅有创建多个线程池的才可能会并发进行。

*/

public class ThreadManager { public static final String DEFAULT_SINGLE_POOL_NAME = "DEFAULT_SINGLE_POOL_NAME"; private static ThreadPoolProxy mLongPool = null; private static Object mLongLock = new Object(); private static ThreadPoolProxy mShortPool = null; private static Object mShortLock = new Object(); private static ThreadPoolProxy mDownloadPool = null; private static Object mDownloadLock = new Object(); private static Map<String, ThreadPoolProxy> mMap = new HashMap<String, ThreadPoolProxy>(); private static Object mSingleLock = new Object(); /** 获取下载线程 */ public static ThreadPoolProxy getDownloadPool() { synchronized (mDownloadLock) { if (mDownloadPool == null) { mDownloadPool = new ThreadPoolProxy(3, 3, 5L); } return mDownloadPool; } } /** 获取一个用于运行长耗时任务的线程池,避免和短耗时任务处在同一个队列而堵塞了重要的短耗时任务,通经常使用来联网操作 */ public static ThreadPoolProxy getLongPool() { synchronized (mLongLock) { if (mLongPool == null) { mLongPool = new ThreadPoolProxy(5, 5, 5L); } return mLongPool; } } /** 获取一个用于运行短耗时任务的线程池,避免由于和耗时长的任务处在同一个队列而长时间得不到运行。通经常使用来运行本地的IO/SQL */ public static ThreadPoolProxy getShortPool() { synchronized (mShortLock) { if (mShortPool == null) { mShortPool = new ThreadPoolProxy(2, 2, 5L); } return mShortPool; } } /** 获取一个单线程池,全部任务将会被依照增加的顺序运行,免除了同步开销的问题 */ public static ThreadPoolProxy getSinglePool() { return getSinglePool(DEFAULT_SINGLE_POOL_NAME); } /** 获取一个单线程池,全部任务将会被依照增加的顺序运行。免除了同步开销的问题 */ public static ThreadPoolProxy getSinglePool(String name) { synchronized (mSingleLock) { ThreadPoolProxy singlePool = mMap.get(name); if (singlePool == null) { singlePool = new ThreadPoolProxy(1, 1, 5L); mMap.put(name, singlePool); } return singlePool; } } public static class ThreadPoolProxy { private ThreadPoolExecutor mPool; private int mCorePoolSize; private int mMaximumPoolSize; private long mKeepAliveTime; private ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long keepAliveTime) { mCorePoolSize = corePoolSize; mMaximumPoolSize = maximumPoolSize; mKeepAliveTime = keepAliveTime; } /** 运行任务,当线程池处于关闭,将会又一次创建新的线程池 */ public synchronized void execute(Runnable run) { if (run == null) { return; } if (mPool == null || mPool.isShutdown()) { //參数说明 //当线程池中的线程小于mCorePoolSize。直接创建新的线程增加线程池运行任务 //当线程池中的线程数目等于mCorePoolSize,将会把任务放入任务队列BlockingQueue中 //当BlockingQueue中的任务放满了,将会创建新的线程去运行。 //可是当总线程数大于mMaximumPoolSize时,将会抛出异常,交给RejectedExecutionHandler处理 //mKeepAliveTime是线程运行完任务后,且队列中没有能够运行的任务,存活的时间,后面的參数是时间单位 //ThreadFactory是每次创建新的线程工厂 mPool = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), Executors.defaultThreadFactory(), new AbortPolicy()); } mPool.execute(run); } /** 取消线程池中某个还未运行的任务 */ public synchronized void cancel(Runnable run) { if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { mPool.getQueue().remove(run); } } /** 取消线程池中某个还未运行的任务 */ public synchronized boolean contains(Runnable run) { if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { return mPool.getQueue().contains(run); } else { return false; } } /** 立马关闭线程池。并且正在运行的任务也将会被中断 */ public void stop() { if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { mPool.shutdownNow(); } } /** 平缓关闭单任务线程池,可是会确保全部已经增加的任务都将会被运行完成才关闭 */ public synchronized void shutdown() { if (mPool != null && (!mPool.isShutdown() || mPool.isTerminating())) { mPool.shutdownNow(); } } } }
  • 广播
    … has leaked IntentReceiver … Are you missing a call to unregisterReceiver()?
    这个错误我们如今公司的代码还有大把的了。

    这么解决,一个大神的方法

简单粗暴
private void unregisterReceiverSafe(BroadcastReceiver receiver) {try {getContext().unregisterReceiver(receiver);} catch (IllegalArgumentException e) {// ignore}
}

接下来的几个感觉大家应该都不会出太大的问题吧

Cursor

try{}catch(){}
finally{
cur.close();
cur=null;
}

adapter (如今都用recycleview了。感觉写这个有点儿鸡肋)

会造成内存溢出代码:
public View getView  (int position, View convertView, ViewGroup parent)  {View  view   =   new  View();XXX                   XXXreturn    view;
}
修正后的代码:
public View getView (int position, View convertView, ViewGroup parent)  {if  (convertView  ==  null)  {convertView   =  new View();XXX                     XXX}  else  {XXX                     XXX}
}

Bitmap

不用的时候调用 recycle(),把他清理掉
也能够用lrucache等方法,这就不做具体介绍。

转载请注明:http://blog.csdn.net/wanghao200906/article/details/50426881
就这样吧。忙里偷闲写了个博客,总结一下,事实上内存溢出的问题都是 不小心导致的,避免起来也比較easy。

文章有点儿长 读完了 :辛苦了您內,0基础文章大神勿喷


http://lihuaxi.xjx100.cn/news/280425.html

相关文章

机器人视觉的九大挑战

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达本文转自&#xff1a;新机器视觉机器人视觉解决方案是我们实现机器人视野的几大挑战。即便变得越来越简单易用&#xff0c;还是有一些棘手的问题。很多因素影响机器人在环…

android dslr控制软件,DSLR Controller

DSLR Controller中文名字是单反控制器&#xff0c;是一款专业的单反手机控制端软件&#xff0c;用户可以使用该手机软件控制单反&#xff0c;调节单反的相关数据&#xff0c;控制拍摄&#xff0c;非常方便&#xff0c;需要的可以下载使用&#xff01;软件简介DSLR Controller是…

BFS之三(单向bfs和康托压缩)

//poj 1077 Eight#include <iostream> //单向bfs和康托压缩#include<string>using namespace std;bool visited[1000000];int fac[]{1,1,2,6,24,120,720,5040,40320,362880}; //9!表int cantor(int arr[]) {int temp,num1; //当排列为…

Python实现环形链表详解

这篇文章主要为大家详细介绍了Python实现环形链表&#xff0c;文中示例代码介绍的非常详细&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下 本文实例为大家分享了Python实现环形链表的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下 我们将…

为什么数据科学不值得?

作者 | Dario Radečić 译者 | 陈思 本应是 21 世纪最热门的工作&#xff0c;实际上却可能没有那么火爆。数据科学已经陪伴我们一段时间了&#xff0c;它已经不再只是一个热门词汇。人们和公司都利用它创造了价值和金钱&#xff0c;但它真的是未来的职业吗&#xff1f; 作者注…

干货 | OpenCV中KLT光流跟踪原理详解与代码演示

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达本文转自&#xff1a;opencv学堂稀疏光流跟踪(KLT)详解在视频移动对象跟踪中&#xff0c;稀疏光流跟踪是一种经典的对象跟踪算法&#xff0c;可以绘制运动对象的跟踪轨迹与…

时间序列的建模新思路:清华、李飞飞团队等提出强记忆力E3D-LSTM网络

作者 | Yunbo Wang,、Lu Jiang、 Ming-Hsuan Yang、Li-Jia Li、Mingsheng Long、Li Fei-Fei译者 | 凯隐编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】如何对时间序列进行时空建模及特征抽取&#xff0c;是RGB视频预测分类&#xff0…

Spring Cloud Consul 之Greenwich版本全攻略

点击上方“方志朋”&#xff0c;选择“置顶或者星标”你的关注意义重大&#xff01;什么是ConsulConsul是HashiCorp公司推出的开源软件&#xff0c;使用GO语言编写&#xff0c;提供了分布式系统的服务注册和发现、配置等功能&#xff0c;这些功能中的每一个都可以根据需要单独使…