一般内存泄漏(traditional memory leak)的原因是: 由忘记释放分配的内存导致的。(如Cursor忘记关闭等)
逻辑内存泄漏(logical memory leak)的原因是: 当应用不再需要这个对象,当仍未释放该对象的所有引用。
如果持有对象的强引用,垃圾回收器是无法在内存中回收这个对象。
在Android中,导致潜在内存泄漏的陷阱不外乎两种:
1)全局进程(process-global)的static变量。这个无视应用的状态,持有Activity的强引用的怪物。
2)活在Activity生命周期之外的线程。没有清空对Activity的强引用。
具体有以下几种:
1.Static Activities
在类中定义了静态Activity变量,把当前运行的Activity实例赋值于这个静态变量。 如果这个静态变量在Activity生命周期结束后没有清空,就导致内存泄漏。因为static变量是贯穿这个应用的生命周期的,所以被泄漏的Activity就会一直存在于应用的进程中,不会被垃圾回收器回收。
2.Static Views
View在内存中也是比较耗资源的,如果把View定义为static,加载到视图树上(View Hierachy),也会造成内存泄漏。
3.Inner Classes
内部类的优势之一就是可以访问外部类,不幸的是,导致内存泄漏的原因,就是内部类持有外部类实例的强引用。
4.Anonymous Classes
相似地,匿名类也维护了外部类的引用。所以内存泄漏很容易发生,当你在Activity中定义了匿名的AsyncTsk。当异步任务在后台执行耗时任务期间,Activity不幸被销毁了(译者注:用户退出,系统回收),这个被AsyncTask持有的Activity实例就不会被垃圾回收器回收,直到异步任务结束。
5.Handler
同样道理,定义匿名的Runnable,用匿名类Handler执行。Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息队列MessageQueue中,在Message消息没有被处理之前,Activity实例不会被销毁了,于是导致内存泄漏。
6.Threads
7.TimerTask
只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏。
8.Sensor Manager
最后,通过Context.getSystemService(int name)可以获取系统服务。这些服务工作在各自的进程中,帮助应用处理后台任务,处理硬件交互。如果需要使用这些服务,可以注册监听器,这会导致服务持有了Context的引用,如果在Activity销毁的时候没有注销这些监听器,会导致内存泄漏。