转载请注明出处 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泄漏。

  1. public class MainActivity extends Activity {
  2. private static Drawable mDrawable;
  3. @Override
  4. protected void onCreate(Bundle saveInstanceState) {
  5. super.onCreate(saveInstanceState);
  6. setContentView(R.layout.activity_main);
  7. ImageView iv = new ImageView(this);
  8. mDrawable = getResources().getDrawable(R.drawable.ic_launcher);
  9. iv.setImageDrawable(mDrawable);
  10. }
  11. }

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

  1. public class MainActivity extends Activity
  2. {
  3. static Demo sInstance = null;
  4. public void onCreate(BundlesavedInstanceState){
  5. }
  6.  
  7. class Demo{
  8. void do Something(){
    }
  9. }
  10. }

(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的内部类,就更容易出现内存泄露的问题。

  1. SampleActivity extends Activity {
  2. new AsyncTask<Void, Void, Void>() {
  3. @Override
  4. protected Void doInBackground(Void... params) {
  5. doSomething();
  6. return null;
  7. }
  8. }.execute();
  9.  
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. doSomething();
  14. }
  15. }).start();
  16. }

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

  1. private static class MyHandler extends Handler {
  2.  
  3. private final WeakReference<Context> context;
  4.  
  5. private MyHandler(Context context) {
  6. this.context = new WeakReference<Context>(context);
  7. }
  8.  
  9. @Override
  10. public void handleMessage(Message msg) {
  11. switch (msg.what) {
  12.  
  13. }
  14. }
  15. }
  16.  
  17. private final MyHandler mHandler = new MyHandler(this);
  18.  
  19. private static final Runnable sRunnable = new Runnable() {
  20. @Override
  21. public void run() {
  22.  
  23. }
  24. };
  25.  
  26. @Override
  27. protected void onCreate(Bundle savedInstanceState) {
  28. super.onCreate(savedInstanceState);
  29. setContentView(R.layout.activity_home);
  30. // 发送一个10分钟后执行的一个消息
  31. mHandler.postDelayed(sRunnable, 600000);
  32. }

(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. Call me evilxr

    我是Evilxr,博客新开第一天:希望自己能坚持下去!之前友友推荐的是oschina,使用了一段时间发现oschina经常抽风,再者自己平时也有关注一些博客觉得cnblogs也不错,开博的初衷是想记录 ...

  2. 数位DP之奥义

    恩是的没错数位DP的奥义就是一个简练的dfs模板 int dfs(int position, int condition, bool boundary) { ) return (condition ? ...

  3. Nginx-解读内置非默认模块 ngx_http_stub_status_module

    1.Background ngx_http_stub_status_module 是一个 Nginx 的内置 HTTP 模块,该模块可以提供 Nginx 的状态信息.默认情况下这个模块是不被编译进来的 ...

  4. Nginx-默认不压缩HTTP/1.0与长连接的关系

    在移动的 http 请求量和联通不相上下的前提下,移动的 http response 带来的网络流量是联通的 2.5 倍.移动大概有 3 成的请求都没有做压缩,而联通几乎都是经过压缩的.那些没有经过压 ...

  5. chrome/ie中图片底部多出几像素问题

    如果给图片的父元素设置背景色,则图片的底部就会多出几像素,chrome/IE/FF中均是如此,如下图: 代码如下,就是简单的div中放张图片: <!doctype html> <ht ...

  6. sp_who_lock

    USE MyDataBase GO /****** Object: StoredProcedure [dbo].[sp_who_lock] Script Date: 4/10/2015 ******/ ...

  7. HTML JavaScripts

    JavaScript JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处理. ...

  8. HTML meta 头部的一些内容

    <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable= ...

  9. Linux的nm查看动态和静态库中的符号

    功能 列出.o .a .so中的符号信息,包括诸如符号的值,符号类型及符号名称等.所谓符号,通常指定义出的函数,全局变量等等. 使用 nm [option(s)] [file(s)] 有用的optio ...

  10. 解决未能加载文件或程序集“Newtonsoft.Json ...."或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

    今天遇到了一个比较坑的问题,琢磨了好久... 因为需要引用一个第三方的类库,三方的类库引用的是Newtonsoft.Json.dll 版本7.0.0而我的项目中引用的是Newtonsoft.Json. ...