垃圾回收就是回收内存中再也不使用的对象。java
步骤有2步:算法
1. 查找内存中再也不使用的对象并发
(1)引用计数法:有一个缺点,不能检测到环的存在oracle
(2)根搜索算法:经过一系列名为“GC Roots”的对象做为起始点,当一个对象到GC Roots没有任何引用链相连时,则证实此对象是不可用的性能
2.释放这些对象占用的内存线程
(1) 标记-复制 :它将可用内存容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完以后,就将还存活的对象复制到另一块上面,而后在把已使用过的内存空间一次理掉。它的优势是实现简单,效率高,不会存在内存碎片。缺点就是须要2倍的内存来管理。设计
(2) 标记-清理:清除算法分为“标记”和“清除”两个阶段:首先标记出须要回收的对象,标记完成以后统一清除对象。它的优势是效率高,缺点是容易产生内存碎片。指针
(3) 标记-整理:标记操做和“标记-清理”算法一致,后续操做不仅是直接清理对象,而是在清理无用对象完成后让全部 存活的对象都向一端移动,并更新引用其对象的指针。由于要移动对象,因此它的效率要比“标记-清理”效率低,可是不会产生内存碎片。对象
新生代和老生代:blog
因为对象的存活时间有长有短,因此对于存活时间长的对象,减小被gc的次数能够避免没必要要的开销。这样咱们就把内存分红新生代和老年代,新生代存放刚建立的和存活时间比较短的对象,老年代存放存活时间比较长的对象。这样每次仅仅清理年轻代,老年代仅在必要时时再作清理能够极大的提升GC效率,节省GC时间。
java垃圾收集器的历史:
1. Serial(串行)收集器
2. Parallel(并行)收集器
3. CMS(并发)收集器
4. G1(并发)收集器
(1)程序调用System.gc时能够触发;
(2)系统自身来决定GC触发的时机。系统判断GC触发的依据:根据Eden区和From Space区的内存大小来决定。当内存大小不足时,则会启动GC线程并中止应用线程。
oracle官方计划在jdk9中将G1变成默认的垃圾收集器,以替代CMS。
G1的设计原则就是简单可行的性能调休。将新生代,老生代的物理空间划分取消了。
细节:
G1算法将堆划分为若干个区域(Region),它仍然属于分代收集器。不过,这些区域的一部分包含新生代,新生代的垃圾收集依然采用暂停全部应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。老年代也分红不少区域,G1收集器经过将对象从一个区域复制到另一个区域,完成了清理工做。这就意味着,在正常的处理过程当中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有cms内存碎片问题的存在了。
在G1中,还有一种特殊的区域,叫Humongous区域。 若是一个对象占用的空间超过了分区容量50%以上,G1收集器就认为这是一个巨型对象。这些巨型对象,默认直接会被分配在年老代,可是若是它是一个短时间存在的巨型对象,就会对垃圾收集器形成负面影响。为了解决这个问题,G1划分了一个Humongous区,它用来专门存放巨型对象。若是一个H区装不下一个巨型对象,那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。
PS:在java 8中,持久代也移动到了普通的堆内存空间中,改成元空间。
最后,G1提供了两种GC模式,Young GC和Mixed GC,两种都是Stop The World(STW)的。