转载请注明出处 http://www.cnblogs.com/weiwangnuanyang/p/5704596.html

先讲一下内存泄漏的概念:内存泄露是指无用对象持续占有内存,或者内存得不到及时释放,从而造成的内存空间的浪费。

我们都知道,Java中对象的存储在堆中,它们由GC回收。GC为了能够正确释放对象,会监控每个对象的运行状况(申请、引用、被引用、赋值等)。Java会使用有向图的方法进行管理内存,实时监控对象是否可以达到,如果不可到达,则就将其回收。也就是说,一个对象不被任何引用所指向,则该对象会在被GC发现的时候被回收;另外,如果一组对象中只包含互相的引用,而没有来自它们外部的引用(例如有两个对象A和B互相持有引用,但没有任何外部对象持有指向A或B的引用),这仍然属于不可到达,同样会被GC回收。

因此Java中造成内存泄漏的一般原因都是长生命周期的对象持有了短生命周期的对象,使得短生命周期的对象不能被释放;或者资源未及时关闭。

下面总结了一些造成android中内存泄漏的常见原因:

1. 大量同一个类的对象被常驻内存的Map(比如单例模式的静态成员变量)持有,未及时移除。

比如观察者模式中的监听者,注册后没有反注册。

再比如使用一个很重的对象作为Map的key,导致这个类所引用的所有对象都不能释放。

所以如果注册监听时,监听的对象常驻内存,一定要反注册。尽量不使用很重的对象作为Map的key,如果有这样的需求,一定要及时清空Map.

2. Activity中使用非静态内部类或者匿名内部类,或者引用着Activity的类被其他长生命周期类持有。Activity持有其View层以及所有相关联资源的引用,如果无用的Activity得不到释放,会泄漏大量资源。

下面列举一些常见的情况。

(1)将Activity作为单例模式的静态成员变量。

(2)静态对象间接引用Activity.如下面代码的引用关系mDrawable -> ImageView -> MainActivity,导致Activity泄漏。

public class MainActivity extends Activity {
private static Drawable mDrawable;
@Override
protected void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
setContentView(R.layout.activity_main);
ImageView iv = new ImageView(this);
mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
iv.setImageDrawable(mDrawable);
}
}

(3)Activity的内部类作为其静态成员变量。非静态的内部类和匿名内部类都会隐式地持有其外部类的引用,如下Demo会持有MainActivity,

public class MainActivity extends Activity
{
static Demo sInstance = null;
public void onCreate(BundlesavedInstanceState){
} class Demo{
void do Something(){
}
}
}

(4)Handler作为内部类引起的内存泄漏。如果Handler是非静态内部类,Handler 会持有Activity的引用。当Activity退出而Handler还有延迟处理的消息没有处理完,会导致Activity不能回收,反复如此会导致内存泄露。

具体分析可以参考 http://droidyue.com/blog/2014/12/28/in-android-handler-classes-should-be-static-or-leaks-might-occur/

(5)线程引起的内存泄漏。下面的代码中Tread运行不定时,在run方法未执行完的期间会一直持有Activity的引用。而AsyncTask的问题更严重写,AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

 SampleActivity extends Activity {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
doSomething();
return null;
}
}.execute(); new Thread(new Runnable() {
@Override
public void run() {
doSomething();
}
}).start();
}

我们首先想到的解决方法是使用静态内部类,但是静态内部类又不持有Activity对象,所有当需要使用Activity的时候可以使用弱引用。

private static class MyHandler extends Handler {

    private final WeakReference<Context> context;

    private MyHandler(Context context) {
this.context = new WeakReference<Context>(context);
} @Override
public void handleMessage(Message msg) {
switch (msg.what) { }
}
} private final MyHandler mHandler = new MyHandler(this); private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { }
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// 发送一个10分钟后执行的一个消息
mHandler.postDelayed(sRunnable, 600000);
}

(6)Context引起的泄漏。一个app的Application会持有一个生命周期与app一样长的Context,每一个组件会持有一个与组件生命周期一样长的Context.当比Activity生命周期长的对象持有了Activity的Context,会引起Activity不能被回收。所以在允许的情况下,尽量使用ApplicationContext。

3. 资源未及时关闭

在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接、网络连接、磁盘文件等,打开这些物理资源之后必须显式关闭,否则将会引起资源泄漏。

JVM的垃圾回收机制不会回收这些资源,垃圾回收机制属于java内存管理的一部分,它只是负责回收堆内存中分配出来的内存,至于程序中打开的物理资源,垃圾回收机制是无能为力的。

通常在finally块中关闭资源,有一个细节就是,最好在关闭资源时进行判空。

4. 合理管理Bitmap

以上部分内容摘自:

http://blog.csdn.net/mxm691292118/article/details/51020023

【原创】android内存管理-内存泄漏原因的更多相关文章

  1. [Android 性能优化系列]内存之基础篇--Android怎样管理内存

    大家假设喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处(http://blog.csdn.net/kifile),再次感谢 原文地 ...

  2. Unity游戏Mono内存管理及泄漏

    UWA工具 https://yq.aliyun.com/articles/435553 Unity游戏Mono内存管理及泄漏 https://wetest.qq.com/lab/view/135.ht ...

  3. 内存管理 & 内存优化技巧 浅析

    内存管理 浅析 下列行为都会增加一个app的内存占用: 1.创建一个OC对象: 2.定义一个变量: 3.调用一个函数或者方法. 如果app占用内存过大,系统可能会强制关闭app,造成闪退现象,影响用户 ...

  4. Java中的垃圾回收机制&内存管理&内存泄漏

    1. Java在创建对象时,会自动分配内存,并当该对象引用不存在的时候,释放这块内存. 为什么呢? 因为Java中使用被称为垃圾收集器的技术来监视Java程序的运行,当对象不再使用时,就自动释放对象所 ...

  5. 构造函数,C++内存管理,内存泄漏定位

    构造函数 1.构造顺序 虚基类构造函数,基类构造函数,类对象构造函数,自己的构造函数 2.必须使用初始化列表 (1) 引用成员,常量成员: (2) 基类没默认构造函数(自己重载覆盖了), (3)类对象 ...

  6. Spark内核| 调度策略| SparkShuffle| 内存管理| 内存空间分配| 核心组件

    1. 调度策略 TaskScheduler会先把DAGScheduler给过来的TaskSet封装成TaskSetManager扔到任务队列里,然后再从任务队列里按照一定的规则把它们取出来在Sched ...

  7. Linux内核内存管理-内存访问与缺页中断【转】

    转自:https://yq.aliyun.com/articles/5865 摘要: 简单描述了x86 32位体系结构下Linux内核的用户进程和内核线程的线性地址空间和物理内存的联系,分析了高端内存 ...

  8. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  9. 【转】Android中的内存管理--不错不错,避免使用枚举类型

    原文网址:http://android-performance.com/android/2014/02/17/android-manage-memory.html 本文内容翻译自:http://dev ...

随机推荐

  1. RMQ算法模板

    分别写了下标从0和1开始的两种 #include<stdio.h> #include<string.h> #include<algorithm> #include& ...

  2. 基于android平台的出题软件---- 每日30题

    本app共编写了3个activity,1.Mainactivity作为主界面.2.surface,用来显示随机出的题.3.showresult,用来打印所有做过的题(含结果),一个类function用 ...

  3. TD Rigging Demo Reel 性感美女绑定展示

    161455520158189 这是一个充满回忆的Demo,非常怀念之前的工作生活,也特别感谢我长春的老哥张总对我的帮助与指导,不光是工作中,在生活上也让我有很大的收获.这个一直都觉得做的不够好,也从 ...

  4. Linux-awk直接修改原文件

    #注意:重定向符号后面的文件名需要加双引号 awk '{print > "file"}' file

  5. 自定义HttpModule的一些经验--配置篇

    http://www.cnblogs.com/MyaSky/articles/2134954.html 自定义HttpModule的一些经验--配置篇 自定义web模块,需继承System.Web.I ...

  6. mybatis generator使用(基于maven)

    1.添加maven依赖 <dependency> <groupId>org.mybatis.generator</groupId> <artifactId&g ...

  7. 百度地图api2.0体验

    前言:这两天在做百度地图的功能,查看了百度官网的api完成了基本功能 api地址http://developer.baidu.com/map/jshome.htm 注意是javascript API ...

  8. maven 项目无法发布,无法编译的解决办法

    1 Web Deployment Assembly信息都合理2 重新clear项目,让JAVA代码重新生成.class文件在target目录中

  9. TEX学习笔记

    整理在这里, 方便以后容易查找. 毕竟每个tex的模板有些不一样. Beamer: Latex beamer 学习总结 http://blog.sina.com.cn/s/blog_6cf921f30 ...

  10. java 记事本 - 实例

    记事本记事本实例中使用了以下知识1.ui界面2.io流3.事件监听4.图形5.JFileChooser 类,用于打开文件,另存为文件.弹出文件选择器对话框 学习重点:JFileChooser,有很多方 ...