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);
} @Override
public 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() {
@Override
public void run() { /* ... */ }
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); //10分钟之后发送消息
mHandler.postDelayed(sRunnable, 1000 * 60 * 10); // 退回到上一个Activity
finish();
}
} @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 XXX
return 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基础文章大神勿喷

android中常见的内存泄漏和解决的方法的更多相关文章

  1. Android中常见的内存泄漏

    为什么会产生内存泄漏? 当一个对象已经不需要再使用了,本该被回收时,而有另外一个正在使用的对象持有它的引用从而导致它不能被回收,这导致本该被回收的对象不能被回收而停留在堆内存中,这就产生了内存泄漏. ...

  2. .NET中常见的内存泄漏和解决办法

    在.NET中,虽然CLR的GC垃圾回收器帮我们自动回收托管堆对象,释放内存,最大程度避免了"内存泄漏"(应用程序所占用的内存没有得到及时释放),但.NET应用程序"内存泄 ...

  3. Android开发 |常见的内存泄漏问题及解决办法

    在Android开发中,内存泄漏是比较常见的问题,有过一些Android编程经历的童鞋应该都遇到过,但为什么会出现内存泄漏呢?内存泄漏又有什么影响呢? 在Android程序开发中,当一个对象已经不需要 ...

  4. Android开发——常见的内存泄漏以及解决方案(二)

    )Android2.3以后,SoftReference不再可靠.垃圾回收期更容易回收它,不再是内存不足时才回收软引用.那么缓存机制便失去了意义.Google官方建议使用LruCache作为缓存的集合类 ...

  5. Android开发——常见的内存泄漏以及解决方案(一)

    0. 前言   转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52333954 Android的内存泄漏是Android开发领域永恒的 ...

  6. Js中常见的内存泄漏场景

    常见的内存泄漏场景 内存泄漏Memory Leak是指程序中已动态分配的堆内存由于疏忽或错误等原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果.内存泄漏并非指内 ...

  7. android 中如何分析内存泄漏

    转载:http://blog.csdn.net/fulinwsuafcie/article/details/8363218 前提条件: 1,电脑安装了java 运行环境 2,手机端开启了 USB 调试 ...

  8. Android性能优化之常见的内存泄漏

    前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我们可以借助LeakCanary.MAT等工具来检 ...

  9. 老李分享:Android性能优化之内存泄漏1

    老李分享:Android性能优化之内存泄漏   前言 对于内存泄漏,我想大家在开发中肯定都遇到过,只不过内存泄漏对我们来说并不是可见的,因为它是在堆中活动,而要想检测程序中是否有内存泄漏的产生,通常我 ...

随机推荐

  1. django自带权限控制系统的使用和分析

    1.django的权限控制相关表及其相互间的关系: django的所有权限信息存放在auth_permission表中,用户user和用户组group都可以有对应的权限permission.分别存放在 ...

  2. bzoj3687简单题(dp+bitset优化)

    3687: 简单题 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 861  Solved: 399[Submit][Status][Discuss] ...

  3. U - Three displays

    Problem description It is the middle of 2018 and Maria Stepanovna, who lives outside Krasnokamensk ( ...

  4. Redis hash结构 和常用命令

    Redis 数据结构 -- 哈希 hash 是 一个 String 类型的field 和 value 的映射表 hash 的键值 对在内存中的一种无序的状态 命令 说明 备注 hdel key fie ...

  5. Laravel5.1学习笔记6 响应

    基本响应 附加头信息到响应 附加Cookie到响应 其他响应 View视图响应 JSON响应 File下载 重定向 重定向到命名路由 重定向到控制器Action 附带闪回Session数据重定向 响应 ...

  6. CSS选择器优先级计算

    优先级从高到低排列,浏览器优先满足前面的规则 1,!important优先级最高 2,内联样式 3,作者>读者>浏览器 4,优先级权重加法 id选择器+100/个 类/伪类选择器+10/个 ...

  7. js仿新浪游戏频道导航条

    js仿新浪游戏频道导航条 在线演示本地下载

  8. OPPO R11 R11plus系列 解锁BootLoader ROOT Xposed 你的手机你做主

    首先准备好所有要使用到的文件 下载链接:https://share.weiyun.com/5WgQHtx 步骤1. 首先安装驱动 解压后执行 Install.bat 部分电脑需要禁用驱动程序签名才可以 ...

  9. AO如何获取SDE数据库中的数据

    /// <summary> /// 获取Table类型表的记录 /// </summary> /// <param name="relationCheckCla ...

  10. python tips:类的专有属性

    实例通常能够调用类的属性,但是有些属性是类专有的,实例无法调用. 实例调用方法时查找属性时,首先在自己的__dict__中找,找不到去类中找,在类中能够找到的属性都位于dir(cls)中,如果类的某些 ...