垃圾回收(Garbage Collection,GC),就是经过垃圾收集器把内存中没用的对象清理掉。垃圾回收涉及到内容:算法
判断对象是否已死:找出哪些对象是已经死掉的,之后不会再用到的。性能优化
判断对象是否已死的方法:引用计数算法和可达性分析算法。多线程
给每个对象添加一个引用计数器,每当有一个地方引用它时,计数器值加 1;每当有一个地方不在引用它时,计数器值减 1,这样只要计数器的值不为 0,就说明还有地方引用它,它就不是无用的对象。并发
这种方法看起来很是简单,可是目前许多主流的虚拟机都没有选用这种算法来管理内存,原理就是当某些对象之间互相引用时,没法判断出这些对象是否已死。性能
算法的基本思路:经过一系列的称为GC Roots
的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到 GC Roots 没有任何引用链相连时,则证实此对象是不可用的。学习
在 Java 语言中,可做为 GC Roots 的对象包括下面几种:优化
经常使用的垃圾回收算法有三种:spa
分为 标记 和 清除 两个阶段,首先标记出全部须要回收的对象,标记完成后统一回收全部被标记的对象。线程
不足之处:3d
为了解决 "标记-清除" 算法内存碎片化的缺陷而被提出的算法。根据内存容量将内存划分为相等大小的两块。每次只使用其中一块,当这一块内存用完了,就将还存活着的对象复制到另一块上面,而后再把已使用过的内存空间一次清理掉。
优势:效率要高于标记-清除算法,不会产生过多的碎片。在对象存活率较高时要进行较多的复制操做,效率会较低。
缺点:可用内存被压缩到本来的一半。且存储对象增多的话,Copying 算法的效率会大大下降。
先对可用的对象进行标记,而后全部被标记的对象都向一端移动,最后直接清理掉端边界之外的内存。
优势:自带整理功能,这样不会产生大量不连续的内存空间,适合老年代的大对象存储。
分代收集算法是目前大部分 JVM 所采用的方法,其核心思想就是根据对象存活的不一样生命周期将内存划分为不一样的域(把堆内存分为新生代和老年代)。老年代的特色是每次垃圾回收只有少许对象须要被回收,新生代的特色是每次垃圾回收时都有垃圾须要被回收,所以能够根据不一样区域选择不一样的回收算法。
新生代与复制算法
目前大部分 JVM 的 GC 对于新生代都采用 Copying 算法,由于新生代中每次垃圾回收都会回收大部分对象,即要复制的对象比较少,一般并非按照 1:1 来划分新生代。通常将新生代划分为一块较大的 Eden 区和两个较小的 Survivor 区(From Survivor、To Survivor),每次使用 Eden 区和其中一块 Survivor 区,当进行回收的时候,将该两块空间中还存活的对象复制到另一块 Survivor 空间中。
老年代与标记复制算法
老年代由于每次只会回收少许对象,于是采用 Mark-Compact 算法
如今常见的垃圾收集器有以下几种:
Serial 收集器是最基本、发展历史最悠久的收集器。Serial 收集器是一个单线程的收集器,可是这个"单线程"的意义并不只仅说明它只会使用一个 CPU 或一条收集线程去完成垃圾收集工做,更重要的是在它进行垃圾收集时,必须暂停其余全部的工做线程,直到它收集结束(Stop The World)。
Serial 收集器是虚拟机运行在 Client 模式下的默认新生代收集器。
优势:简单而高效,对于限定单个 CPU 的环境来讲,Serial 收集器没有线程交互的开销,专心作垃圾收集能够得到最高的单线程收集效率。
适用场景:适合运行在 Client 模式下的虚拟机。
ParNew 收集器是 Serial 收集器的多线程版本,可使用多条线程进行垃圾收集。
ParNew 是运行在 Server 模式下的虚拟机中首选的新生代收集器,只有 ParNew 收集器可以与 CMS 收集器配合工做。
ParNew 默认开启的收集线程数与 CPU 的数量相同,在 CPU 很是多的环境下,可使用 -XX:ParallelGCThreads
参数来限制垃圾收集的线程数。
Parallel Scavenge 是一个新生代收集器,使用复制算法实现,并行的多线程收集器,吞吐量优先的收集器。
Parallel Scavenge 收集器的目标是 达到一个可控制的吞吐量(Throughput)。
Parallel Scavenge 收集器提供了两个参数用于精确控制吞吐量,分别是控制最大垃圾收集停顿时间的 -XX:MaxGCPauseMillis
参数以及设置吞吐大小的 -XX:GCTimeRatio
参数。
MaxGCPauseMills:容许的值是一个大于 0 的毫秒数,收集器将尽量地保证内存回收话费的时间不超过设定值。
GCTimeRatio:参数的值是一个大于 0 且小于 100 的证书,就是垃圾收集时间占总时间的比率,至关因而吞吐量的倒数。
Serial Old 是 Serial 收集器的老年代版本,单线程收集器,使用"标记-整理"算法。
适合 Client 模式下的虚拟机使用。
在 Server 模式下,还有两大用途:
Parallel Old 是 Parallel Scavenge 收集器的老年代版本,使用多线程和"标记-整理"算法。从 JDK 1.6 开始提供。 在注重吞吐量以及 CPU 资源敏感的场合,均可以优先考虑 Parallel Scavenge 加 Parallel Old 收集器。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS 收集器是基于"标记-清除"算法实现的,它的运做过程相对于前面几种收集器来讲更复杂一些,整个过程分为 4 个步骤:
CMS 是一款优秀的收集器,主要优势:并发收集、低停顿。可是 CMS 还存在如下 3 个缺点:
G1(Garbage First) 收集器是当今收集器技术发展的最前沿成果之一。
G1 收集器是基于 标记-整理 算法实现的收集器,它不会产生空间碎片,能够很是精确地控制停顿。
G1 是一款 面向服务端应用 的垃圾收集器。与其余 GC 收集器相比,G1 具有以下特色:
Stop-The-World
停顿时间,部分其余收集器本来须要停顿 Java 线程执行的 GC 动做,G1 收集器仍然能够经过并发的方式让 Java 程序继续执行。参数 | 描述 |
---|---|
UseSerialGC | 虚拟机运行在 Client 模式下的默认值,打开此开关后,使用 Serial + Serial Old 的收集器组合进行内存回收 |
UseParNewGC | 使用 ParNew + Serial Old 收集器组合进行内存回收 |
UseConcMarkSweepGC | 使用 ParNew + CMS + Serial Old 的收集器组合进行内存回收。Serial Old 收集器将做为CMS收集器出现 Concurrent Mode Failure 失败后的后备收集器使用 |
UseParallelGC | 虚拟机运行在 Server 模式下的默认值,使用 Parallel Scavenge + Serial Old(PS MarkSweep)的收集器组合进行内存回收 |
UseParallelOldGC | 使用 Parallel Scavenge + Parallel Old 的收集器组合进行内存回收 |
SurvivorRatio | 新生代中 Eden 区域与 Survivor 区域的容量比值,默认为8,表明Eden:From:To=8:1:1 |
PretenureSizeThreshold | 直接晋升到老年代的对象大小,设置这个参数后,大于这个参数的对象将直接在老年代分配 |
MaxTenuringThreshold | 晋升到老年代的年龄。每一个对象在坚持过一次 Minor GC 以后,年龄就加 1,当超过这个参数值时就进入老年代 |
UseAdaptiveSizePolicy | 动态调整 Java 堆中各个区域的大小以及进入老年代的年龄 |
HandlePromotionFailure | 是否容许分配担保失败,即老年代的剩余空间不足以应对新生代的整个 Eden 和 Survivor 区的全部对象都存活的极端状况 |
ParallelGCThreads | 设置并行 GC 时进行内存回收的线程数 |
GCTimeRatio | GC 时间占总时间的比率,默认为99,即容许 1% 的 GC 时间,仅在使用 Parallel Scavenge 收集器时生效。 |
MaxGCPauseMillis | 设置 GC 的最大停顿时间。仅在使用 Parallel Scavenge 收集器时生效 |
CMSInitiationOccupancyFraction | 设置 CMS 收集器在老年代空间诶使用多少后触发垃圾收集。默认值为68%,仅在使用 CMS 收集器时生效 |
UseCMSCompactAtFullCollection | 设置 CMS 收集器在完成垃圾收集后是否要进行一次内存碎片整理。仅在使用 CMS 收集器时生效 |
CMSFullGCsBeforeCompaction | 设置 CMS 收集器在进行若干次垃圾收集后再启动一次内存碎片整理。仅在使用 CMS 收集器时生效 |
-XX:PretenureSizeThreshold
参数,令大于这个设置值的对象直接在老年代中分配。这样作的目的是避免在 Eden 区及两个 Survivor 区以前发生大量的内存拷贝。Minor GC:指发生在新生代(包括 Eden 区和 Survivor 区)的垃圾收集动做,由于 Java 对象大多都具有朝生夕灭的特性,因此 Minor GC 很是频繁,通常回收速度也比较快。
Major GC:指发生在老年代的 GC,出现了 Major GC,常常会伴随至少一次 Minor GC(但非绝对的,在 Parallel Scavenge 收集器的收集策略里就有直接进行 Major GC 的策略选择过程)。Minor GC 的速度通常会比 Minor GC 的速度慢 10 倍以上。
Full GC:针对新生代、老年代、元空间(Metaspace、Java8 以上版本取代 Perm gen)的全局范围的 GC。Full GC 不等于 Major GC,也不等于 Minor GC + Major GC,发生 Full GC 须要看使用了什么垃圾收集器组合,才能解释是什么样的垃圾回收。
推荐推荐: