转载请注明出处 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. codeMirror的简单使用,js比较文本差异(标注出增删改)

    最近项目需要使用比较文本的差异的功能,在同事的推荐下,使用js脚本来比较,所以codeMirror变成了选择. 当然codeMirror中有其他功能,比较文本差异的只是其中一个功能,本人不在此做介绍, ...

  2. 在线markdown编辑器

    https://www.zybuluo.com/mdeditor http://mahua.jser.me/

  3. linux下的代码比较工具

    在linux下有很多不错的代码比较工具:meld.DiffMerge.xxdiff.diffuse.Kompare等... diff : 文件比较工具用于比较计算机上的文件的内容,找到他们之间相同与不 ...

  4. 调试新技能get - powershell

    1. win+r -> powershell_ise 2. debug-process 3. type processname....WITHOUT ".exe"

  5. Shell编程菜鸟基础入门笔记

    Shell编程基础入门     1.shell格式:例 shell脚本开发习惯 1.指定解释器 #!/bin/bash 2.脚本开头加版权等信息如:#DATE:时间,#author(作者)#mail: ...

  6. NULL指针、零指针、野指针

    1.1.空指针 如果 p 是一个指针变量,则 p = 0; p = 0L; p = '\0'; p = 3 - 3; p = 0 * 17;p=(void*)0; 中的任何一种赋值操作之后, p 都成 ...

  7. python3-day2-python基础2

    一.for循环 for循环是我们编程中非常常用的一种循环,以下就是for循环在python中的一些应用实例: 1.单层for循环 #!/usr/bin/env python3#-*- coding: ...

  8. linux---mysql安装

    一.查询本机是否有mysql service mysql status 二.检查已安装的mysql版本 mysql –uroot -p status 三.查看已安装的mysql的组件 dpkg --g ...

  9. 2017微软秋招A题

    时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 There is an integer array A1, A2 ...AN. Each round you may ch ...

  10. OAF_文件系列9_实现OAF解析Excel并读取至数据库JXL

    ddd puroder. webui. poLineExcelImport.java