您的位置:首页 > 移动开发 > Android开发

Android 内存泄露的一点个人小见解

2015-12-23 15:46 573 查看
首先向我上面转载了2篇关于内存泄露的文章表达一下诚挚的谢意,最近看了很多关于内存泄露的文章,这两篇感觉作者写的很认真,感觉必须要谢谢他们的好心分享。不过既然读了别人的文章,也转载了,总该说点什么吧。下面诚当写读后感了。

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我不认为可以归类为内存泄露,语气说内存泄露 不如说内存溢出,因为这些内存 在不用的时候是可以回收的。对于这一点,我表达一下个人态度,希望有大神能够帮忙解惑。

好了,今天就说这两点,下次有什么好的想法再来写写。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: