Java内存回收机制
在java中,内存的分配大致分为:堆,栈、方法区、本地方法区,程序计数器;本地方法区,程序计数器,栈随着线程的生灭而生灭,不需要我们关心内存,方法区和堆才是垃圾收集器所关注的部分。
1 Java中对象是否存活算法
如何判断一个对象可以被回收?在Java中,采用的是可达性分析算法:通过一系列的"GC Roots"对象为起点,向下搜索,搜索的路径叫做引用链,当某些对象无法与任意一个"GC Roots"对象的引用链向连,则这个对象是不可用的。
GC Root对象
1、栈中引用的对象
2、方法区中类静态属性引用的对象
3、方法区中常亮引用的对象
4、本地方法栈JNI引用的对象
Java中的四种引用
1、强引用(Strong Refernce):Java中最常用的引用,像,new Object();只要强引用还在,对象就永远不会被回收被引用的对象;
2、软引用(Soft Refernce):在系统发生内存溢出异常之前,会将这类对象列进回收范围进行第二次回收,如果这次回收内存依然不足,才会发生内存溢出异常。
3、弱引用(Weak Refernce):这类引用的对象,只能存活到下次GC之前,不论内存是否充足,都会被回收;
4、虚引用(Phantom Refernce):这类应用完全不会对对象的什么周期构成影响,也无法通过虚引用获取对象,该引用的目的是在GC回收时收到一个系统通知;
2 垃圾收集算法
在垃圾被回收以前,需要对对象进行判断处理,在Java中,采用分代收集算法,将对象分为新生代和老年代,针对这两种情况,分别采用不同的算法;
1、新生代:采用复制算法,将内存按照1:1分为2部分,每次使用其中的一个,当使用的这个内存用完,就将还存活的对象复制到另一块上,然后删除这块上的所有对象,优点是实现简单,运行高效,不过在实际中,并不是按照1;1的比例分配,而是按照8:1:1的比例分为3块(Eden:Survivor:Survivor),每次使用Eden和一个Survivor,回收时,将还存活的对象复制到另一块Survivor上,在删除Eden和用过的Survivor;
2、老年代:采用"标记-清理"或者"标记-整理"算法。"标记-清理",分为标记和清理2个阶段,先将需要清理的对象标记,最后统一清理,不过有2大缺点:效率问题,空间碎片化;"标记-整理",同样分为2部分,标记,清理,在清理部分,不是直接清除垃圾,而是先将所以存活的对象向一端移动,最后在清理边界以外的内存。