Android内存泄漏学习总结

Android应用程序开发以Java语言为主,而Java编程中一个很重要的问题就是内存的使用,Java的垃圾回收机制是的很多开发者不太关心内存的使用生命周期,只是一味的申请内存,却不去手动释放和废弃内存,造成内存的泄漏,从而引起很多的问题,导致程序的崩溃。Android的虚拟机Dalvik VM和java虚拟机JVM没有很大的区别,只是在字节码上做了优化,因此Android应用开发中同样会有内存泄漏的问题存在,由于android平台主要应用于嵌入式产品开发,可使用的内存资源更加少,因此对android开发来说,应该全面的了解android程序的内存管理机制,避免内存泄漏。
1.内存泄漏概念
内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配,大小任意的,使用完后必须显示释放的内存。应用程序一般使用malloc,calloc,realloc,new等函数从堆内存中分配到一块内存,使用完成之后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。
在java程序中,如果已经不再使用一个对象,但仍有引用指向它,GC就无法回收,该对象占用的内存也不能被使用,这就造成了内存的泄漏。也许有人会说实例对象的内存泄漏非常小,不会引起大的问题。但是,如果程序反复长期做此操作,引起的内存不断泄漏,最终将使得程序没有内存使用,只能被系统kill。在该情况下,内存泄漏会导致比较严重的后果:
1)程序运行后置之不理,并且随着时间的流失消耗越来越多的内存(比如服务器上的后台任务,尤其是嵌入式系统中的后台任务,这些任务可能被运行后很多年都置之不理);
2)新的内存被频繁的分配,比如当显示电脑游戏或者动画视频画面时;
3)程序能够请求未被释放的内存(比如共享内存),甚至是在程序终止的时候;
4)泄漏在操作系统内部发生;
5)泄漏在系统关键驱动中发生;
6)内存非常有限,比如在嵌入式系统或便携设备中;
7)当运行于一个终止是内存并不自动释放的操作系统时,而且一旦丢失就只能通过重启恢复。
2开发人员注意事项
对于开发者,对待内存泄漏应该以防为主,以治为辅,因为一旦造成内存泄漏,追查原因不是很容易,虽然有工具能够利用,但是还是会耗费一些不必要的时间精力用来分析内存使用报告和反复搜查代码。为了能够开发高性能和高质量的软件,防止内存泄漏,我们应该知道什么时候使用gc,什么时候使用recycle,以及到底用不用finalization,因为Java对内存的分配只是需要new开发者不需要显示释放内存,但这会造成内存泄漏问题产生的几率更多。我们应该:
1.了解Java的四种引用方式,比如强引用、软引用,弱引用以及虚引用。一些复杂的程序在长期运行中可能有OOM的异常。
2.并不要过多的指望gc,不用的对象可以显示的设置为空,比如obj=null,java的gc使用的是一个有向图,判断一个对象是否有效看的是其他的对象恩能够到达这个对象的顶点,有向图的相对与链表、二叉树来说开销多很多。
3.android为每个程序分配的对内存可以通过Runtime类的totalMemory() freeMemory()两个方法获取VM的一些内存信息,对于系统heap内存获取,可以通过Dalvik.VMRuntime类的getMinimumHeapSize()方法获取最小可用堆内存,同时显示释放软引用可以调用该类的gcSoftRefrences()方法,获取更多的运行内存。
4.对于多线程的处理,如果并发的线程很多,同时有频繁的创建和释放,可以通过concurrent类的线程池解决线程创建的效率瓶颈。
5.不要在循环中创建过多的本地变量。
关于Java中的引用的介绍:
在Java中内存管理,引用分为四大类,强引用 HardReference、弱引用WeakReference、软引用SoftReference 和虚引用PhantomReference。它们的区别也很明显,HardReference 对象是即使虚拟机内存吃紧抛出 OOM 也不会导致这一引用的对象被回收,而 WeakReference等更适合于一些数量不多,但体积稍微庞大的对象,在这四个引用中,它是最容易被垃圾回收的,而我们对于显示类似 Android Market 中每个应用的AppIcon时可以考虑使用SoftReference来解决内存不至于快速回收,同时当内存短缺面临JavaVM崩溃抛出OOM前时,软引用将会强制回收内存,最后的虚引用一般没有实际意义,仅仅观察GC的活动状态,对于测试比较实用同时必须和ReferenceQueue一起使用。对于一组数据,我们可以通过HashMap的方式来添加一组SoftReference对象来临时保留一些数据,同时对于需要反复通过网络获取的不经常改变的内容,可以通过本地的文件系统或数据库来存储缓存。
3 Android(java)中常见的引起内存泄漏
Android 主要应用在嵌入式设备当中,而嵌入式设备由于一些众所周知的条件限制,通常都不会有很高的配置,特别是内存是比较有限的。如果我们编写的代码当中有太多的对内存使用不当的地方,难免会使得我们的设备运行缓慢,甚至是死机。为了能够使得Android应用程序安全且快速的运行,Android 的每个应用程序都会使用一个专有的Dalvik 虚拟机实例来运行,它是由Zygote 服务进程孵化出来的,也就是说每个应用程序都是在属于自己的进程中运行的。一方面,如果程序在运行过程中出现了内存泄漏的问题,仅仅会使得自己的进程被kill 掉,而不会影响其他进程(如果是system_process 等系统进程出问题的话,则会引起系统重启)。另一方面Android 为不同类型的进程分配了不同的内存使用上限,如果应用进程使用的内存超过了这个上限,则会被系统视为内存泄漏,从而被kill 掉。
3.1查询数据库没有关闭游标
程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。
3.2 构造Adapter时,没有使用缓存的convertView
以构造ListView 的BaseAdapter 为例,在BaseAdapter 中提高了方法:
public View getView(int position, View convertView, 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 回收listitem 的view 对象的过程可以查看。
3.3 Bitmap对象不在使用时调用recycle()释放内存
有时我们会手工的操作Bitmap 对象,如果一个Bitmap 对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。
4 leakcanary检测内存泄漏
4.1 LeakCanary介绍
LeakCanary 是一个开源的在debug版本中检测内存泄漏的java库。
让我们来看看一个cait的例子:
class Cat {
}
class Box {
  Cat hiddenCat;
}
class Docker {
  static Box container;
}
Box box = new Box();
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;


创建一个RefWatcher实例,然后给它一个对象让它观察:
// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);


当检测出泄漏的时候,你会自动得到一个漂亮的泄漏线索:
*GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance
我们知道你的时间宝贵,因此我们让它非常好设置。只需几行代码,LeakCanary就能自动检测Activity的泄漏:
public class ExampleApplication extends Application {
  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}



 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值