`

避免Android中context引起的内存泄露

 
阅读更多

Context是我们在编写Android程序经常使用到的对象,意思为上下文对象。 常用的有Activity的Context还是有Application的Context。Activity用来展示活动界面,包含了很多的视图,而视图又含有图片,文字等资源。在Android中内存泄露很容易出现,而持有很多对象内存占用的Activity更加容易出现内存泄露,开发者需要特别注意这个问题。

本文讲介绍Android中Context,更具体的说是Activity内存泄露的情况,以及如何避免Activity内存泄露,加速应用性能。

Drawable引起的内存泄露

Drawable引起内存泄露这个问题是比较隐晦,难以察觉的。在阅读了Romain Guy的Avoiding memory leaks,结合grepcode查看源码才明白了。

在Android系统中,当我们进行了屏幕旋转,默认情况下,会销毁掉当前的Activity,并创建一个新的Activity并保持之前的状态。在这个过程中,Android系统会重新加载程序的UI视图和资源。假设我们有一个程序用到了一个很大的Bitmap图像,我们不想每次屏幕旋转时都重新加载这个Bitmap对象,最简单的办法就是将这个Bitmap对象使用static修饰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
  TextView label = new TextView(this);
  label.setText("Leaks are bad");
  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
  setContentView(label);
}

但是上面的方法在屏幕旋转时有可能引起内存泄露,无论是咋一看还是仔细看这段代码,都很难发现哪里引起了内存泄露。

当一个Drawable绑定到了View上,实际上这个View对象就会成为这个Drawable的一个callback成员变量,上面的例子中静态的sBackground持有TextView对象lable的引用,而lable只有Activity的引用,而Activity会持有其他更多对象的引用。sBackground生命周期要长于Activity。当屏幕旋转时,Activity无法被销毁,这样就产生了内存泄露问题。

2.3.7及以下版本Drawable的setCallback方法的实现

1
2
3
public final void setCallback(Callback cb) {
    mCallback = cb;
}

好在从4.0.1开始,引入了弱引用处理这个问题,弱引用在GC回收时,不会阻止GC回收其指向的对象,避免了内存泄露问题。

1
2
3
public final void setCallback(Callback cb) {
    mCallback = new WeakReference<Callback>(cb);
}

单例引起的内存泄露

单例是我们比较简单常用的一种设计模式,然而如果单例使用不当也会导致内存泄露。 比如这样一个例子,我们使用饿汉式初始化单例,AppSettings我们需要持有一个Context作为成员变量,如果我们按照下面的实现其实是有问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class AppSettings {    
    private Context mAppContext;
    private static AppSettings sInstance = new AppSettings();
    //some other codes
    public static AppSettings getInstance() {
      return sInstance;
    }
    public final void setup(Context context) {
        mAppContext = context;
    }
}

sInstance作为静态对象,其生命周期要长于普通的对象,其中也包含Activity,当我们进行屏幕旋转,默认情况下,系统会销毁当前Activity,然后当前的Activity被一个单例持有,导致垃圾回收器无法进行回收,进而产生了内存泄露。

解决的方法就是不持有Activity的引用,而是持有Application的Context引用。代码如下修改

1
2
3
public final void setup(Context context) {
    mAppContext = context.getApplicationContext(); 
}

访问这里了解更多关于单例模式的问题

条条方法返回Context

通常我们想要获取Context对象,主要有以下四种方法

  • View.getContext,返回当前View对象的Context对象,通常是当前正在展示的Activity对象。
  • Activity.getApplicationContext,获取当前Activity所在的(应用)进程的Context对象,通常我们使用Context对象时,要优先考虑这个全局的进程Context。
  • ContextWrapper.getBaseContext():用来获取一个ContextWrapper进行装饰之前的Context,可以使用这个方法,这个方法在实际开发中使用并不多,也不建议使用。
  • Activity.this 返回当前的Activity实例,如果是UI控件需要使用Activity作为Context对象,但是默认的Toast实际上使用ApplicationContext也可以。

其他内存泄露问题

避免内存泄露须谨记

  • 不要让生命周期长于Activity的对象持有到Activity的引用
  • 尽量使用Application的Context而不是Activity的Context
  • 尽量不要在Activity中使用非静态内部类,因为非静态内部类会隐式持有外部类实例的引用(具体可以查看细话Java:”失效”的private修饰符了解)。如果使用静态内部类,将外部实例引用作为弱引用持有。
  • 垃圾回收不能解决内存泄露,了解Android中垃圾回收机制

参考文章

分享到:
评论

相关推荐

    避免 Android中Context引起的内存泄露

    本文将深入探讨由Context引起的内存泄露问题,特别是Activity和Drawable相关的内存泄露,以及单例模式下的内存管理。 首先,我们来理解一下Activity和内存泄露的关系。Activity是Android应用中的主要组件,用于展示...

    android内存泄露的检测和排查

    5. **使用弱引用**:在可能引起内存泄漏的地方,比如自定义View、Adapter等,可以使用WeakHashMap来存储对对象的引用,这样当对象不再被其他地方引用时,会自动回收。 接下来,我们通过一个锁屏内存泄漏的例子来...

    Android内存优化——常见内存泄露及优化方案

    1. 使用弱引用(WeakReference/SoftReference):对于可能引起内存泄露的对象,可考虑使用弱引用或软引用,以便在内存不足时自动回收。 2. 避免在静态变量或单例中持有Context:尽量使用Application Context,而不是...

    android_context详解

    ### Android Context详解 ...开发者应该深入了解`Context`的工作原理,正确使用`Context`提供的API,同时注意避免常见的使用陷阱,如内存泄漏和生命周期问题,从而编写出更健壮、高效的Android应用。

    5个Android开发中比较常见的内存泄漏问题及解决办法

    在Android开发中,内存泄漏是一个严重的问题,它会导致应用程序占用过多内存,进而引发内存溢出,最终可能导致应用崩溃。本文将深入探讨5个常见的内存泄漏问题及其解决方案。 1. **单例造成的内存泄漏** 单例模式...

    Android开发最常见的5大内存泄漏

    在Android应用开发中,内存泄漏是一个非常重要的问题,它会导致应用程序占用过多的内存,从而影响性能,甚至引发应用崩溃。本文将深入探讨Android开发中最常见的五种内存泄漏情况,并提供相应的解决方案。 一、静态...

    Android 内存泄漏调试经验分享

    #### 二、Android(Java)中常见的容易引起内存泄漏的不良代码 ##### (一) 查询数据库没有关闭游标 当在Android中执行SQL查询操作时,如果没有正确关闭游标(`Cursor`),则可能导致内存泄漏。这是因为`Cursor`对象...

    Android 内存泄露

    在Android开发中,内存泄漏是一个严重的问题,它会导致应用程序占用过多的内存,进而影响性能,甚至可能导致应用崩溃。本文将深入探讨Android内存泄漏的概念、常见场景、预防措施以及检测方法。 首先,Android...

    android内存分析

    总的来说,理解Android的内存管理机制,合理使用对象,及时释放资源,避免静态变量和线程引起的内存泄露,是优化应用性能和防止内存问题的关键。开发者需要时刻关注内存使用情况,利用工具如MAT(Memory Analyzer ...

    Android开发最常见的5大内存泄漏.docx

    在Android开发中,内存泄漏是开发者需要密切关注的问题,因为它直接影响到应用的性能和稳定性。内存泄漏发生时,不再使用的对象由于被其他活跃对象引用而无法被垃圾回收器正常清理,导致内存占用持续增加,最终可能...

    Android学习资料之内存优化.zip

    - 静态变量:静态变量的生命周期与应用程序进程相同,如果持有Activity或其他容易引起内存泄露的对象,会导致内存泄露。 - 非静态内部类:非静态内部类会隐式持有对外部类的引用,如果外部类是Activity,可能导致...

    android内存泄露

    在Android开发中,内存泄露是一个严重的问题,它会导致应用程序占用过多的内存,影响性能,甚至导致应用崩溃。本文将深入探讨Android内存泄露的概念、原因、检测方法以及如何进行有效修复。 首先,我们要理解什么是...

    Android_内存泄漏研究及调试.doc )

    #### 二、Android (Java) 中常见的容易引起内存泄漏的不良代码 在Android应用开发中,不当的内存管理可能导致内存泄漏。下面列举了一些常见的内存使用不当的情况: ##### (一) 查询数据库没有关闭游标 **描述**:...

    Android防止内存溢出浅析

    - 使用WeakReference或SoftReference来持有对Activity、Context或其他易引起内存泄露的对象的引用。 - 避免在静态变量中存储非静态数据,特别是与UI相关的对象。 通过以上策略,开发者可以更有效地管理Android应用...

    Android编程中避免内存泄露的方法总结

    作为我的一项工作,我仔细研究了Android应用的内存泄露问题,大多数情况下它们是由同一个错误引起的,那就是对一个上下文(Context)保持了长时间的引用。 在Android中,上下文(Context)被用作很多操作中,但是大...

    android内存优化详解

    本文将深入探讨Android的内存机制、内存溢出问题、static关键字的影响以及线程导致的内存泄露。 首先,理解Android的内存机制至关重要。Android程序主要使用Java编写,其内存管理遵循Java的自动垃圾回收(GC)机制...

    Android中的内存泄漏

    内存泄漏在Android开发中是一个非常重要的概念,...总之,理解和避免Android中的内存泄漏是提升应用性能和稳定性的重要环节。开发者需要时刻关注内存管理,确保对象能够在不再使用时被正确释放,以维持系统的健康运行。

Global site tag (gtag.js) - Google Analytics