Android 内存泄露的一点个人小见解
2015-12-23 15:46
573 查看
首先向我上面转载了2篇关于内存泄露的文章表达一下诚挚的谢意,最近看了很多关于内存泄露的文章,这两篇感觉作者写的很认真,感觉必须要谢谢他们的好心分享。不过既然读了别人的文章,也转载了,总该说点什么吧。下面诚当写读后感了。
2篇文章都提到了很重要的一点 static 的使用不当是致命的,那么为什么static 会有这么大的影响力呢。这里,我觉得有必要去考量一下
堆Heap 和 栈Stack 这两个关键点。做开发的我们基本都知道函数 、临时变量、变量 是存储在栈中,常量 是存储在 堆中。那么详细的来看一下下面的2个例子。
我转载的上一篇文章中说道,这段代码没有问题,但是当我们频繁的横竖屏切换的时候 Activity 就内存泄露了,为什么呢。我们都知道如果支持横竖屏切换的Activity在很竖屏切换的时候会重新走一次生命周期,也就是会系统新开辟一个Activity的实例。理论上来讲就是既然有新的,就得就应该要回收了,如果发生了内存泄露,也就是说前一个Activity没有办法被回收,那么为什么没有办法被回收呢,从关系图来看,似乎没有任何一个其他引用会使用到上一个Activity,他应该可以被回收啊,但是此时问题就出现在
这里,我首先说明一下,我们要记住,Android每一个 的Application都是一个单独的进程,而我们的static 的sInstance是和整个应用程序是等同生命周期的(没有实例化的除外),那么既然和整个Application等同生命周期,这也就意味着它只要在当前整个Application退出后才会被系统回收。那么是不是只要当前Activity 包含静态变量 就不可以被回收呢?答案很明显 不是,如果是的话,那么基本上估计我们的每一个应用程序都会有问题,这里我们需要注意,Java的内存自动回收机制,当一个引用不被其他引用关联的时候,他就可以回收了,那么答案很明显了,如果我们的静态变量
一旦关联了我们的Activity ,那么这个Activity就不能被回收了。那么怎么关联的呢,他是一个内部类。
我们来看下一个
这里我们都知道,使用静态变量去保存图片会极大加快运行速度(横竖屏切换的时候不用重新加载图片资源),那么为什么会导致内存泄露呢,这里我们不做过多描述了,我们知道sBackground 等同Application生命周期,但是关键是为什么sBackground 导致了整个Activity的内存泄露呢。
其一,我们知道
先看看android 2.3的Drawable.Java对setCallback的实现:
[java] view
plaincopy
public final void setCallback(Callback cb){
mCallback = cb;
}
也就是说sBackground linkTo TextView,但是既然是Linkto TextView,又怎么关联上了整个Activity了呢?
对的,问题出在了这个this,this对应了这个Activity,所以TextView 无法回收,Activity也不可以回收。
这里,我们可以考虑这样一种情况,如果我们
这样Activity会不会内存泄露呢,很明显应该不会了吧,但是这样做真的可以吗,应该是不可以的,Activity虽然不泄露了但是我们的TextView 依然泄露了。所以Google给出了解决方案是这样的。
再看看android 4.0的Drawable.Java对setCallback的实现:
[java] view
plaincopy
public final void setCallback(Callback cb){
mCallback = newWeakReference<Callback> (cb);
}
Static 关键字说完了,我们来说一下
“构造Adapter时,没有使用缓存的 convertView”
我们都知道 重用convertView 能够加快程序的运行速度,convertView 越复杂越明显,但是对于这个归为内存泄露,我保留一些疑问,我们都知道,Android inflateView 是占用大量的内存的,如果我们的ListView 一次性加载上千条数据,并且如果我们没有重用convertView ,那么如果convertView 稍微复杂一点,基本上就OOM了,但是这里的OOM我不认为可以归类为内存泄露,语气说内存泄露 不如说内存溢出,因为这些内存 在不用的时候是可以回收的。对于这一点,我表达一下个人态度,希望有大神能够帮忙解惑。
好了,今天就说这两点,下次有什么好的想法再来写写。
2篇文章都提到了很重要的一点 static 的使用不当是致命的,那么为什么static 会有这么大的影响力呢。这里,我觉得有必要去考量一下
堆Heap 和 栈Stack 这两个关键点。做开发的我们基本都知道函数 、临时变量、变量 是存储在栈中,常量 是存储在 堆中。那么详细的来看一下下面的2个例子。
public class MainActivityextends Activity { static Demo sInstance = null; @Override public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (sInstance == null) { sInstance= new Demo(); } } class Demo { voiddoSomething() { System.out.print("dosth."); } } }
我转载的上一篇文章中说道,这段代码没有问题,但是当我们频繁的横竖屏切换的时候 Activity 就内存泄露了,为什么呢。我们都知道如果支持横竖屏切换的Activity在很竖屏切换的时候会重新走一次生命周期,也就是会系统新开辟一个Activity的实例。理论上来讲就是既然有新的,就得就应该要回收了,如果发生了内存泄露,也就是说前一个Activity没有办法被回收,那么为什么没有办法被回收呢,从关系图来看,似乎没有任何一个其他引用会使用到上一个Activity,他应该可以被回收啊,但是此时问题就出现在
static Demo sInstance = null;
这里,我首先说明一下,我们要记住,Android每一个 的Application都是一个单独的进程,而我们的static 的sInstance是和整个应用程序是等同生命周期的(没有实例化的除外),那么既然和整个Application等同生命周期,这也就意味着它只要在当前整个Application退出后才会被系统回收。那么是不是只要当前Activity 包含静态变量 就不可以被回收呢?答案很明显 不是,如果是的话,那么基本上估计我们的每一个应用程序都会有问题,这里我们需要注意,Java的内存自动回收机制,当一个引用不被其他引用关联的时候,他就可以回收了,那么答案很明显了,如果我们的静态变量
一旦关联了我们的Activity ,那么这个Activity就不能被回收了。那么怎么关联的呢,他是一个内部类。
我们来看下一个
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); }
这里我们都知道,使用静态变量去保存图片会极大加快运行速度(横竖屏切换的时候不用重新加载图片资源),那么为什么会导致内存泄露呢,这里我们不做过多描述了,我们知道sBackground 等同Application生命周期,但是关键是为什么sBackground 导致了整个Activity的内存泄露呢。
其一,我们知道
先看看android 2.3的Drawable.Java对setCallback的实现:
[java] view
plaincopy
public final void setCallback(Callback cb){
mCallback = cb;
}
也就是说sBackground linkTo TextView,但是既然是Linkto TextView,又怎么关联上了整个Activity了呢?
TextView label = new TextView(this);
对的,问题出在了这个this,this对应了这个Activity,所以TextView 无法回收,Activity也不可以回收。
这里,我们可以考虑这样一种情况,如果我们
TextView label = new TextView(getApplicationContext());
这样Activity会不会内存泄露呢,很明显应该不会了吧,但是这样做真的可以吗,应该是不可以的,Activity虽然不泄露了但是我们的TextView 依然泄露了。所以Google给出了解决方案是这样的。
再看看android 4.0的Drawable.Java对setCallback的实现:
[java] view
plaincopy
public final void setCallback(Callback cb){
mCallback = newWeakReference<Callback> (cb);
}
Static 关键字说完了,我们来说一下
“构造Adapter时,没有使用缓存的 convertView”
我们都知道 重用convertView 能够加快程序的运行速度,convertView 越复杂越明显,但是对于这个归为内存泄露,我保留一些疑问,我们都知道,Android inflateView 是占用大量的内存的,如果我们的ListView 一次性加载上千条数据,并且如果我们没有重用convertView ,那么如果convertView 稍微复杂一点,基本上就OOM了,但是这里的OOM我不认为可以归类为内存泄露,语气说内存泄露 不如说内存溢出,因为这些内存 在不用的时候是可以回收的。对于这一点,我表达一下个人态度,希望有大神能够帮忙解惑。
好了,今天就说这两点,下次有什么好的想法再来写写。
相关文章推荐
- Android thumbnail显示逻辑
- android measure 流程 (方便记忆)
- Android 淡入淡出效果
- Groovy 文件的api扩展 (可用于gradle)
- android native 程序 bus error 案例分析
- android studio 引入arr包的方法
- Android通过代码模拟物理、屏幕点击事件
- Android RadioButton 图片位置和大小
- android BitmapFactory.Options.inSampleSize用法说明
- Android Service 相关
- Android PullToRefresh 分析之四、扩展RecyclerView
- android开源框架
- 安卓加载大量图片
- Android 线性布局按比例显示
- android使用系统裁剪图片
- Android studio 编译报错 Error:Error converting bytecode to dex:
- Android判断横屏竖屏代码
- Android Activity生命周期以及Fragment生命周期的区别与分析
- Groovy的方法、闭包语法,接口的实现
- Android VideoView简单播放视频