至少在T-Mobile G1上Android应用在堆上分配的内存大小被限制16MB之内。对于手机来讲,这是个不小的内存,可是这仍然远远不能知足一些开发者的需求。可是,即便你不打算使用全部的内存空间,你也应该尽量地少用内存,从而使得其余应用可以运行而不是被杀掉。由于Android可以在内存中保持的应用越多,那么用户切换应用的速度就会越快。做为我工做的一部分,我在作android应用开发的时候也会陷入内存泄漏的问题中,大多数时候内存的泄漏都是因为犯了相同的错误:长期持有了一个Context的引用。
Android上 ,Context能够用于不少操做,可是大部分时候是用来加载以及使用资源。这就是为何全部的widgets在他们的构造函数中接受一个Context参数。在通常的android应用中,你一般有两种Context:分别是Activity和Application。一般的,当咱们的类和方法须要使用到context时,咱们传递的是Activity这个context:
[java] view plain
copy
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
setContentView(label);
}
这意味着views拥有一个对整个activity的引用,也就是引用了你的activity所拥有的一切;一般的,这指的是完整的视图层级结构以及全部它的资源。所以,若是你泄露了一个Context(“ 泄漏 ”意味着你保持着它的一个引用,从而使它不能被垃圾回收机制回收),就意味着你泄漏了不少的内存。若是你不当心, 泄漏一 个activity的全部资源真的很是容易。
当 屏幕的方向发生改变的时候,系统默认将会销毁当前的activity而且建立一个新的activity同时保持着原有的状态。在作这个的时候,Android会从资源从新加载应用的UI。如今,想象一下你写了一个应用,这个应用有一张很大的bitmap。你不想再每一次旋转的时候从新加载它。最简单的方法让bitmap持续做用而不随每个方向而从新加载 ,就是把它放进一个静态域:
[java] view plain
copy
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);
}
这段代码很快,可是错误也很严重:它泄漏了第一个activity,这个在第一次屏幕改变时被建立的activity。当一个Drawable被关联到一个view上,这个view就至关于在drawable上设置的一个回调。在上面的代码片断中,这表示drawable有一个TextView的引用,而这个TextView又拥有一个activity的引用(Context),activity依次引用了几乎全部的东西(取决于你的代码)。
这个例子展现了一个最简单的Context 泄漏的状况,你能够在Home screen 的源码中看到咱们是如何解决这个问题的( 查找unbindDrawables() 方法) ,这就是当activity 被销毁的时候将drawables 的回调设为null 。有趣的是,你可能创造出一系列context泄漏的状况有不少,这很是糟糕。他们会是你很快内存溢出。
有两种简单的方法来避免context 相关的内存泄漏。最显著地一个是避免context 逃出他本身的范围以外。上面的例子就展现了使用静态引用的状况,而内部类和他们对外部类的的隐式引用也是一样危险的。第二种方法是使用Application context 。这个context 的生存周期和你的应用的生存周期同样长,而不是取决于activity 的生存周期。若是你想保持一个长期生存的对象,而且这个对象须要一个context ,记得使用application 对象。你能够经过调用Context.getApplicationContext() or Activity.getApplication() 来得到。
总而言之,想要避免context 相关的内存泄漏 ,记住如下几点:
· 不要对activity 的context 长期引用( 一个activity 的引用的生存周期应该和activity 的生命周期相同)
· 试着使用关于application的 context 来替代和activity相关的context
· 若是一个acitivity 的非静态内部类的生命周期不受控制,那么避免使用它;使用一个静态的内部类而且对其中的activity 使用一个弱引用。解决这个问题的方法是使用一个静态的内部类,而且对它的外部类有一WeakReference,就像在ViewRoot中内部类W所作的就是这么个例子。
· 垃圾回收器不能处理内存泄漏的保障。java
2.集合中对象没清理形成的内存泄漏
咱们一般把一些对象的引用加入到了集合中,当咱们不须要该对象时,并无把它的引用从集合中清理掉,这样这个集合就会愈来愈大。若是这个集合是static的话,那状况就更严重了。android
3,数据库,广播关闭。数据库
4,构造Adapter时,没有使用缓存的convertView
描述:
以构造ListView的BaseAdapter为例,在BaseAdapter中提供了方法:
public View getView(int position, ViewconvertView, ViewGroup parent)
来向ListView提供每个item所须要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化必定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,而后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。由此能够看出,若是咱们不去使用convertView,而是每次都在getView()中从新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用愈来愈大。ListView回收list item的view对象的过程能够查看:
android.widget.AbsListView.java --> voidaddScrapView(View scrap) 方法。
5.Bitmap对象不在使用时调用recycle()释放内存缓存