JVM的自动化内存管理主要是自动给对象分配内存,自动回收分配给对象的内存
垃圾回收垃圾回收的本质是回收无用的内存空间
哪些内存需要回收?什么时候回收?如何回收?
垃圾对象标记判定算法
可达性分析算法判定对象是否需要被回收:通过一系列称为“GCRoots”的根对象作为起始结点集,从这些结点开始,根据引用关系向下搜索,搜索过程所走的路径称为“引用链”,如果某个对象到GC Roots间没有任何引用链相连,也就是说从GC Roots到这个对象不可达,则判定该对象不会再被使用,需要被回收
可作为GC Roots的对象包括
虚拟机栈中局部变量表引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方发法栈中Native方法引用的对象
所有被同步锁(synchronized关键字)持有的对象
即使在可达性分析算法中被判定为不可达的对象,也不一定必须要回收。是否真正要回收至少需要两次标记。如果对象在可达性分析后没有与GC Roots相连接的引用链,进行第一次标记;之后会再进行一次筛选,看此对象是否有必要执行finalize()方法,如果此对象没有重写finallize,或者已经被虚拟机调用过,那么就没有必要执行,此时进行第二次标记。此对象如果被判定为有必要执行finallize的话,会被放入一个队列,有线程去执行它们的finallize方法,在方法执行时,只要重新与引用链上的任一对象发生关联,就可以逃过被回收
部分(Partial GC)收集分为:
Minor GC:只对新生代进行回收
Major GC:只对老年代进行回收
Mixed GC:对整个新生代和部分老年代进行回收
整堆收集Full GC;对整个堆和方法区进行收集(方法区收集废弃的常量和不再引用的类型)
垃圾收集算法
a.标记-清除算法:最基础的垃圾收集算法。首先标记出所有需要回收的对象,然后统一清除掉被标记的对象。
两个缺点:
1.如果java堆中有大量对象,而且大部分是需要被回收的,这时必须进行大量标记和清除的动作,执行效率会降低
2.标记、清除之后会产生大量不连续的内存碎片,导致内存空间的碎片化问题。(程序执行过程中需要分配较大对象时找不到足够的连续内存不得不提前触发另一次垃圾收集动作)
b.标记-复制算法:为解决标记-清除算法的问题,出现了标记-复制算法。最开始出现的是半区复制,将内存按容量分为大小相等的两块,每次只使用其中一块内存分配给对象,内存A和内存B,内存A;当A部分内存不足以分配对象引起内存回收,会把存活的对象
放到B内存中,后把A内存的对象全部清除。再使用B块内存时也这样,如此循环。
优点和缺点:避免内存碎片。缺点是浪费掉一半内存
再后来出现了一种半区复制分代策略:将新生代分为eden区和两块survivor空间,每次分配内存只使用eden区和一块survivor空间。发生垃圾收集时,将Eden区
和survivor空间仍然存活的对象一次性复制到另一块survivor空间上,清理掉Eden区和之前那块
survivor空间。每次回收存活的对象超过另一块survivor空间的大小,还有个“逃生门”的安全设计,通常是分配到老年代。Eden和survivor的空间比是8:1,每
次新生代可用内存为整个新生代的90%,相比之前的半区复制,大大提高了内存利用效率。
c.标记-整理算法
像老年代这种对象存活率较高,不适用于标记-复制算法,每次进行大量的复制操作,效率会特别低。
标记的过程和标记-清除算法一样,后续对可回收对象不是直接进行整理,而是让所有存活的对象向内存空间一端移动,然后直接清除掉边界以外的内存,是一
种移动式的回收算法
CMS收集器:并发低停顿收集器,基于标记-清除算法,整个过程分为4个步骤:初始标记、并发标记、重新标记、并发清除,时间最长的并发标记和并发清除是
可以和用户线程一起工作的
G1收集器:将整个java堆划分为多个大小相等的Region,会优先回收回收价值最大的Region。这也是G1:Garbage-first的由来



