在Android 项目时的防止Memory leak 要注意的事项

本文详细解析了Java内存泄漏问题的原因,通过实例展示了内存泄漏的具体表现,并提供了有效的解决策略,包括如何查看和诊断内存泄漏问题。重点讨论了在Android应用中遇到的内存泄漏问题,特别是与Activity和回调类之间的引用关系导致的内存泄漏,以及提供了解决方案来避免这种情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

一般来说,Java VM是会有Gargage Collect的。但是如果object在其他的object 有reference的话,那VM是不会做cleanup的。

 

常见的例子是在Activity 上发生。

 

因为在a) 由一个activity 跳到另一个activity 或是b)在screen rotation 时,Android 系统会新建一个新的Activity,而原先的Activity 会被释放,最后会被Gargage Collect.。但如果其他的Class 有用上这个Activity ,这个activity 就不会被Gargage Collect,因而引起memory leak 的问题。

 

例子

public class MyActivity extends Activity{

 

public void onCreate(Bundle icicle){

     super.onCreate(icicle);

     Utility.registerCallback(this);

    

}

 

}

 

public class Utility

{

private static Classback m_callback = new Callback();

 

public static void registerCallback(Context c){

     m_callback.registerCallback(c);

}

}

 

public class Callback {

private context m_context;

 

public void registerCallback(Context c){

     m_context=c;

}

 

public void unregisterCallback(Context c){

    if ( c == m_context ){

        m_context=null;

}

}

 

}

 

在以上的例子中,因为class Callback 中的m_context 把 MyActivity 抓着了。 所以在这个Activity完成后,Garage Collect是不可以释放MyActivity 的。

 

一个解决方案是在Activity离开前,释放在外面的reference。  

 

例子

public class MyActivity extends Activity{

 

public void onCreate(Bundle icicle){

     super.onCreate(icicle);

     Utility.registerCallback(this);

    

}

 

public void onDestroy()

{

    super.onDestroy();

    Utility.unregisterCallback(this);

}

 

}

 

public class Utility

{

private static Classback m_callback = new Callback();

 

public static void registerCallback(Context c){

     m_callback.registerCallback(c);

}

public static void unregisterCallback(Context c){

     m_callback.unregisterCallback(c);

}

 

}

 

public class Callback {

private context m_context;

 

public void registerCallback(Context c){

     m_context=c;

}

 

public void unregisterCallback(Context c){

    if ( c == m_context ){

        m_context=null;

}

}

}

 

其他的相关事项

 

1)在SDK中的DigitalClock Widget ,因为DigitalClock要注册一个observer,所以会用把载上DigitalClock widget的Activity作为那个observer。但在SDK的DigitalClock是有一个Bug的,因为在DigitalClock 的onDetachedFromWindow中是没有unregister 那个observer的。 解决方法是自己写一个DigitalClock。详情请看附上的代码(DigitalClockNew.java)。

 

2)在SDK中的Toast的function makeText 是要求传一个Context的,但在Toast的代码中,这个Context是会用做callback上。如果是传Activity作为那个Context的话,那会发生memory leak的问题。解决方法是传 Application Context,而不是ActivityContext。

 

如何查看Memory leak的问题

 

如果怀疑有memory leak的问题,可先执行那个apk在emulator上,然后在PC上执行adb shell,,然后执行ps,查看你的process 的pid。

 

在apk上执行有memory leak可疑的动作后,可以做下面的诊断

1.       执行 dumpsys meminfo <pid>

这个指令显示pid的memory资料。注意是 Activity的 数量,如果数量是不断上升,那就是有memory leak。 注意,因为在未执行Gargage Collect前,Activity是不会被释放的。可以在DDMS上执行手动的Gargage Collect。

2.       把process 的memory dump 出来,看memory leak的所在

先执行 chmod 777 /data/misc,然后执行 kill -10 <pid> ,在 /data/misc 上会看到那个pid 的memory leak,(如heap-dump-tm1265266619-pid1673.hprof )

adb pull ( 如adb pull /data/misc/ heap-dump-tm1265266619-pid1673.hprof 1673.hprof )把这个档案拷回电脑上。

然后,用在PC上执行hprof-conv (如hprof-conv  1673.hprof  1673_a.hprof) 把那个拷回来的hprof转换成 Eclipse Memory Tool 可以支持的格式。

用Eclipse Memory Tool (http://www.eclipse.org/mat/), 打开转换了的memory dump。 在Eclipse Memory Tool 上,按OQL,输入 “select * from instanceof android.app.Activity” , 这个指令可以找所以在系统上是android.app.Activity 的 instance。(详见下图)

如果在object的旁带有“Unknown”的话,那object是可以被Gargage Collect的。要看其他的object是什么原因不可以被Gargage Collect 的话,可以在那个object上right-click,然后选Path to GC Roots, exclude weak/soft reference 。 (weak 和soft reference 都是可以被VM查到的,所以是可以Gargage Collect的。)

 

在Path to GC Roots 中,可以看到WidgetManagerHome 是因为Toast中的inner class TN 把 这个WidgetManagerHome抓住了。(详见下图)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

offbye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值