Android系统运行在Java虚拟机上。作为嵌入式设备,内存往往非常有限。了解Android的垃圾回收机制可以有效防止内存泄漏或者OOM问题。作为介绍性文章,本文将简单讨论垃圾回收和内存泄漏的原理,不会讨论Dalvik虚拟机或native层面的底层机制。1.基础知识在分析垃圾回收之前,我们先回顾一下Java和离散数学的基础知识。实例化:对象是类的实例,创建对象的过程也称为类的实例化。对象是使用类作为模板创建的。比如Carcar=newCar();,我们创建一个Car实例(CreatenewclassinstanceofCar)参考:有些对象的实例化需要其他对象实例,比如ImageView的实例化需要Context对象,意思是ImageView持有对Context的引用(ImageView持有对Context的引用)。有向图:每边都标有有向线段的图称为有向图。Java中的垃圾回收使用有向图进行内存管理。箭头方向表示引用关系,如B←A,即B中需要A,B引用A。可达:在有向图D={S,R}中,对于Si,Sj属于S,如果从Si到Sj存在任何路径,则可以说Si到Sj是可达的。也就是说,当B←A中间的箭头断了,就称为不可达,此时A就无法到达B。当前对象消耗的总内存加上它引用的内存GoogleI/O2011:MemorymanagementforAndroidApps上图中橙色的Object是有向图的起点,它的Shallowheap是100,它的Retainedheap是100+300=400。2、什么是垃圾回收?Java的GC(GarbageCollection,垃圾收集,垃圾回收)机制是Java与C++/C的主要区别之一。作为Java开发人员,您通常不需要编写内存回收和垃圾清理代码。是的内存泄漏和溢出的问题不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,有自动的内存管理和垃圾清理机制。简单来说,这个机制就是标记虚拟机中的内存,决定哪些内存需要回收。根据一定的回收策略,自动回收内存,虚拟机中的内存空间永不停止(NerverStop),防止出现内存泄漏和溢出问题。3、什么情况下需要进行垃圾回收对于GC来说,当程序员创建一个对象时,GC就开始监控对象的地址、大小、使用情况。通常GC使用有向图来记录和管理堆中的所有对象,通过这种方式判断哪些对象“可达”,哪些对象“不可达”。当对象不可达时,即不再引用该对象时,就会被垃圾回收。网上有很多介绍可达关系的文档。如图,第六行,当o2改变方向时,Obj2不再引用main,即不可达,Obj2可能在下一次GC中被回收。developerWorksJava技术4.什么是内存泄漏?当你不再需要一个实例,但该对象仍然被引用时,以防止垃圾收集(Preventfrombeinggarbagecollected)。这种情况称为内存泄漏(MemoryLeak)。下面以HowtoLeakaContext:Handlers&InnerClasses一文的译文为例介绍内存泄漏。看下面的代码它是怎么泄露的?当你启动一个应用程序时,它会自动在主线程中创建一个Looper对象来处理Handler中的消息。Looper实现了一个简单的消息队列,在循环中一个一个的处理Message对象。Application框架的大部分事件(比如Activity生命周期调用、按钮点击等)都在Message中,在Looper的消息队列中一一处理。注意Looper存在于应用程序的整个生命周期中。当你创建一个新的handler对象时,它会被分配到Looper的消息队列中。发送到消息队列的Message会保留一个Handler的引用,因为消息队列在处理这个消息的时候,需要使用[Handler#handleMessage(Message)](http://developer.android.com/reference/android/os/Handler.html#handleMessage(android.os.Message)这个方法。(也就是说只要Message没有被处理,队列中就会一直引用Handler)在java中,非静态内部类和匿名类对它们的外部类都有强引用。静态内部类除外。引用关系现在,我们尝试运行如下代码publicclassSampleActivityextendsActivity{privatefinalHandlermLeakyHandler=newHandler(){@OverridepublicvoidhandleMessage(Messagemsg){//...}}@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//Postamessageanddelayitsexecutionfor10minutes.mLeakyHandler.postDelayed(newRunnable(){@Overridepublicvoidrun(){/*...*/}},1000*60*10);//回到上一个Activity.finish();}}这个程序很简单,大家可以想象一下,应该启动后瞬间关闭,但真的关闭了吗?稍有常识的人都能看出来,它发送了一条Message,十分钟后就会运行,也就是说Message会保留10分钟。这相当于至少10分钟的内存泄漏。最后正确的代码如下ublicclassSampleActivityextendsActivity{/***Instancesofstaticinnerclassesdonotholdanimplicit*referencetotheirouterclass.*/privatestaticclassMyHandlerextendsHandler{privatefinalWeakReference
