避免 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修饰。

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方法的实现

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

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

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

单例引起的内存泄露

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

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引用。代码如下修改

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也可以。

其他内存泄露问题

Android中糟糕的AsyncTask

Android中Handler引起的内存泄露

OnSharedPreferenceChangeListener详解及出现不触发解决办法

避免内存泄露须谨记

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

参考文章

Avoiding memory leaks
Difference between getContext() , getApplicationContext() , getBaseContext() and “this”
Android – what's the difference between the various methods to get a Context?

以上就是对Android Context 内存泄漏的资料整理,后续继续添加相关资料,谢谢大家的支持!

时间: 2024-08-14 00:58:20

避免 Android中Context引起的内存泄露的相关文章

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

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

Android 中Handler引起的内存泄露_Android

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } } 但是,其实上面的代码可能导致内存泄露,当你使用Androi

Android 中Handler引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. public class SampleActivity extends Activity { private final Handler mLeakyHandler = new Handler() { @Override public void handleMessage(Message msg) { // ... } } } 但是,其实上面的代码可能导致内存泄露,当你使用Androi

Android中Handler引起的内存泄露问题解决办法_java

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 复制代码 代码如下: public class SampleActivity extends Activity {   private final Handler mLeakyHandler = new Handler() {     @Override     public void handleMessage(Message msg) {       // ...     }  

Android中Handler可能引起内存泄露

先来看一段代码: 1. private Handler mHandler = new Handler() { 2. @Override 3. public void handleMessage(Message msg) { 4. // ... 5. } 6. }; 这样的写法eclipse会给出一个leak的提示This Handler class should be static or leaks might occur...,表示有可能出现内存泄漏,分析如下: 1) 当一个Handler对象

Android中Context的使用

Context字面意思上下文,位于framework package的android.content.Context中,其实该类为LONG型,类 似Win32中的Handle句柄,很多方法需要通过 Context才能识别调用者的实例,比如说Toast的第一个参数就是 Context,一般在Activity中我们直接用this代替,代表调用者的 实例为Activity,而到了一个button的 onClick(View view)等方法时,我们用this时就会报错,所以我们可能使用Activity

Android 中Context的使用方法详解

Android 中Context的使用方法详解 概要: Context字面意思是上下文,位于framework package的android.content.Context中,其实该类为LONG型,类似Win32中的Handle句柄.很多方法需要通过 Context才能识别调用者的实例:比如说Toast的第一个参数就是Context,一般在Activity中我们直接用this代替,代表调用者的实例为Activity,而到了一个button的onClick(View view)等方法时,我们用t

简析Android的垃圾回收与内存泄露

Android系统是运行在Java虚拟机上的,作为嵌入式设备,内存往往非常有限,了解Android的垃圾回收机制,可以有效的防止内存泄露问题或者OOM问题.本文作为入门文章,将浅显的讨论垃圾回收与内存泄露的原理,不讨论Dalvik虚拟机底层机制或者native层面的问题. 1. 基础 在分析垃圾回收前,我们要复习Java与离散数学的基础. 实例化:对象是类的一个实例,创建对象的过程也叫类的实例化.对象是以类为模板来创建的.比如Car car = new Car();,我们就创造了一个Car的实例

Android垃圾回收机制解决内存泄露问题_Android

在android编码中,会有一些简便的写法和编码习惯,会导致我们的代码有很多内存泄露的问题,在这里做一个已知错误的总结:1.编写单例的时候常出现的错误. 错误方式: public class Foo{ private static Foo foo; private Context mContext; private Foo(Context mContext){ this.mContext = mContext; } // 普通单例,非线程安全 public static Foo getInsta