目录
一、垃圾收集算法
标记-清除算法(Mark-Sweep)
- 概念:首先标记出所有需要回收的对象,在标记完成后统一回收所有标记的对象。
- 特点:
- 效率问题:标记和清除的效率都不高。
- 空间问题:标记清除之后会产生大量不连续的内存碎片,碎片太多可能会导致以后需要分配较大的对象时,因无法找到足够大的连续内存而不得不提前触发另一次垃圾收集的动作。
标记-整理算法(Mark-Compact)
- 概念:首先标记出所有需要回收的对象,在标记完成后让所有存活的对象都向一端移动,然后直接清理掉没有存活对象的另一端。
复制算法(Copying)
- 概念:将可用的内存分为(容量)大小相等的两块,每次只使用其中的一块。当这一块的内存用完后,就将还存活的对象复制到另一块上面,然后再把已使用过的内存块一次性清理掉。
- 特点:
- 运行效率高。
- 空间利用率不高(将内存的大小缩小为原来的一半),存活对象比较大时复制的成本比较高。
- 新生代中各区的划分:
- 新生代中大部分的对象时“朝生夕死”的,所有并不需要安装1:1的比例来划分内存空间。
- 虚拟机将新生代内存分为一块较大的Eden空间和两块较小的Survivor空间(Survivor to和Survivor from),每次使用Eden空间和其中一块Survivor空间。
- HotSpot虚拟机默认Eden和两个Survivor的大小比例是8:1:1,也就是每次新生代中可用内存的空间为整个新生代容量的90%,只有10%的内存会被浪费掉。
- 过程:
- 每次创建对象时,首先会在Eden中分配,若Eden已满,则JVM会进行一次Minor GC;
- Minor GC时,将Eden和Survivor 1中还存活的对象一次性地复制到另外一块Survivor 2空间上,最后清理掉Eden和Survivor 1空间;(说明:Survivor 1中存活的对象是上次gc时复制而来的,jvm并不会直接在survivor上分配对象)。
- 当Survivor to空间不够用时,需要依赖老年代进行分配担保。
- 下次minor gc时,将Eden和Survivor 2中还存活的对象一次性地复制到另外一块Survivor 1空间上,最后清理掉Eden和Survivor 2空间;
分代收集算法
- Java堆分为新生代和老年代,在新生代中采用 复制算法 回收,在老年代中使用 标记-清理 或 标记-整理 算法来回收
- 总结:
- 少量对象的存活,适合复制算法(年轻代)
- 大量对象存活,适合标记清理或者标记压缩(年老代)。
二、垃圾收集的3种模式:
串行收集(Serial GC)
- 概念:一个垃圾收集线程去收集,收集时会将所有的应用线程暂停(stop the world)。
- 特点:适合内存有限的情况,回收慢。
并行收集(Parallel GC)
- 概念:多个垃圾收集线程并行去收集,收集时会将所有的应用线程暂停(stop the world)。
- 特点:效率高,当Heap较大时,系统暂停时间较长。
并发收集(CMS GC)
- 概念:垃圾收集线程和应用线程可以同时工作。
- 特点:
- 优点:old区回收暂停时间短。
- 缺点:整个GC耗时较长、比较耗CPU资源。
三、垃圾收集器
新生代收集器
Serial收集器
- 概念:Serial收集器是一个单线程的收集器,它在进行垃圾收集的时候,必须暂停其他所有的工作线程,直到它搜集结束。(Stop the world)
- 优点:简单而高效(与其它单线存放收集器相比)
- 应用:运行在Client模式下的虚拟机的默认新生代收集器。
- 说明:在桌面应用中,分配给虚拟机管理的内存一般不会很大,收集几十兆或者几百兆的新生代,停顿的时间还不到一秒,只要不是频繁发生,这点停顿还是可以接受的
Parallel Scavenge收集器:吞吐量优先收集器
- 概念:Parallel Scavenge收集器是一个新生代收集器,
- 特点:Parallel Scavenge收集器目标是:达到一个可控制的吞吐量(Throughput)
- 说明:
- 吞吐量 = 运行代码的时间 / (运行代码的时间 + 垃圾收集的时间)
- 吞吐量越高,CPU的利用率就越高,可以尽快的完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
ParNew收集器
- 概念:ParNew收集器其实就是Serial收集器的(并行)多线程版本,即它是使用多线程进行垃圾收集的(多条垃圾收集线程并行工作)。
- 优点:能与CMS收集器搭配工作。
- 应用:运行在Server模式下的虚拟机的新生代收集器。
- 说明:目前只有ParNew可以与CMS收集器搭配使用
老年代收集器
Serial Old收集器
- 概念:Serial Old收集器是Serial收集器的老年代版本,它同样是一个单线程收集器。使用标记-整理算法。
- 应用:
- 在Client模式下的虚拟机使用
- 在Server模式下:
- 与Parallel Scavenge收集器搭配使用
- 作为CMS收集器的后备预案,在并发收集失败(Concurrent Mode Failure)时使用。
Parallel Old收集器
- 概念:Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多线程和标记-整理算法。
- 说明:从jdk1.6开始提供,在注重吞吐量或者对CPU资源敏感的场合,都优先考虑Parallel Scavenge + Parallel Old 组合。
CMS(Concurrent Mark Sweep)收集器
跨代收集器
四、垃圾收集类型
minor gc:
概念:
-
jvm对新生代中垃圾对象的清理称过程为minor gc,又称为young gc。
触发:
-
jvm无法给新对象在新生代Eden区中分配内存时会触发minor gc。
-
由于新对象创建的频率很高,导致新生代中可用的内存往往很快就被耗光,因此minor gc发生的很频繁。
扫描并标记对象
扫描范围:
-
新生代全部区域、老年代的部分区域(dirty card)
扫描方式:
-
可达性(根搜索)算法 + 卡表扫描
-
GC-Root:
-
虚拟机栈(栈帧中的本地变量表)中引用的对象
-
本地方法栈中JNI(即native方法)引用的对象。
-
方法区中:类静态属性引用的对象、常量引用的对象。
-
-
dirty card:
-
卡表中脏元素(值为1)对应的老年代区域(dirty card)中的对象。
-
扫描带来的影响:
-
每次minor gc都会引起STW,一般每次停顿的时间很小,所以young gc带来的停顿看起来并不明显。
五、设置垃圾收集模式和垃圾收集器:
- -XX:+UseSerialGC
- # 使用串行收集模式,即使用Serail + Serail Old 进行回收。
- -XX:+UseParallelGC
- # 虚拟机运行在server模式下的默认选项。新生代使用Parallel Scavenge收集器。注:老年代默认使用Serial Old收集器。
- -XX:+UseParNewGC
- # 新生代使用ParNew收集器。注:老年代默认使用Serial Old收集器。
- -XX:+UseConcMarkSweepGC
- # 新生代使用ParNew收集器 + 老年代使用CMS收集器(并发收集失败(Concurrent Mode Failure)后使用Serial Old收集器)
- -XX:+UseParallelOldGC
- # 新生代使用Parallel Scavenge收集器 + 老年代使用Parallel Old收集器
六、查看当前进程的垃圾收集模式和垃圾收集器:
- 方法一:jinfo PID # 在VM Flags配置中查看
- 方法二:jcmd PID VM.flags # 查看JVM的参数