0213
1.Android内存泄露总结
(1)Java内存分配策略:分别是静态分配,栈式分配,和堆式分配,对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区;
--静态存储区(方法区):主要存放静态数据、全局 static 数据和常量。这块内存在程序编译时就已经分配好,并且在程序整个运行期间都存在。
--栈区 :当方法被执行时,方法体内的局部变量(其中包括基础数据类型、对象的引用)都在栈上创建,并在方法执行结束时这些局部变量所持有的内存将会自动被释放。因为栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
--堆区 : 又称动态内存分配,通常就是指在程序运行时直接 new 出来的内存,也就是对象的实例(包括该对象其中的所有成员变量)。这部分内存在不使用时将会由 Java 垃圾回收器来负责回收。
总结:局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。—— 因为它们属于方法中的变量,生命周期随方法而结束;成员变量全部存储与堆中(包括基本数据类型,引用和引用的对象实体)—— 因为它们属于类,类对象终究是要被new出来使用的;
(2)Java如何管理内存:对于对象和数组而言(通过new创建的),内存的分配是由程序完成的,内存的释放是由GC完成的,这样,减轻了程序员的工作,但是加重了JVM的工作,因为JVM要实时监控Java对象的状态;
(3)Java中的内存泄漏是什么:首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。
(4)Java中的内存泄露场景总会:(Java内存泄漏的根本原因是:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收,这就是Java中内存泄漏的发生场景。具体主要有如下几大类:)
--静态集合类
--监听器
--各种连接
--内部类和外部模块的引用
--单例模式
(5)Android中的内存泄漏场景总会:集合类泄露、单例造成内存泄漏、内名内部累/非静态内部类和异步线程、匿名内部类、Handler、尽量避免使用static成员变量、避免override finalize()、资源及时关闭(对于使用了BraodcastReceiver,ContentObserver,File,游标 Cursor,Stream,Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会被回收,造成内存泄漏)、
--细说单例情况:
--细说Handler情况:
推荐使用静态内部类 + WeakReference 这种方式。每次使用前注意判空。
--简单的说一下 Java 对象的几种引用类型:
使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
另外可以根据对象是否经常使用来判断选择软引用还是弱引用。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。
ok,继续回到主题。前面所说的,创建一个静态Handler内部类,然后对 Handler 持有的对象使用弱引用,这样在回收时也可以回收
Handler 持有的对象,但是这样做虽然避免了 Activity 泄漏,不过 Looper
线程的消息队列中还是可能会有待处理的消息,所以我们在 Activity 的 Destroy 时或者 Stop 时应该移除消息队列
MessageQueue 中的消息。
下面几个方法都可以移除 Message:
public final void removeCallbacks(Runnable r);
public final void removeCallbacks(Runnable r, Object token);
public final void removeCallbacksAndMessages(Object token);
public final void removeMessages(int what);
public final void removeMessages(int what, Object object);