Java 垃圾收集器

面试 GC 相关的问题有:

  • 垃圾回收算法有哪些:引用计数、复制、标清、标压
  • 垃圾收集器有哪些:Serial、Parallel、CMS、G1、ZGC
  • 垃圾回收的方式有哪些:串行、并行、并发标记清理、分区并发------分别对应上方垃圾收集器

GC 算法(引用计数、复制、标清、标压)是理论,垃圾收集器是具体实现

主要垃圾收集器:

  • 串行垃圾收集器-Serial:为单线程环境设计且只使用一个线程进行回收,会暂停所有的用户线程。所以不适合服务器环境
  • 并行垃圾收集器-Parallel:多个垃圾回收线程并行工作,此时用户线程是暂停的,适用于科学计算、大数据处理、首台处理等弱交互场景
  • 并发垃圾收集器-CMS(ConcMarkSweep):并发标记清除。用户线程和垃圾收集器线程同时执行(不一定是并行,也可能是交替执行),不需要暂停用户线程。互联网公司多用它,适用于对响应时间有要求的场景
  • G1-GarbageFirst:将对内存分割成不同的区域然后并发的进行垃圾回收
  • ZGC ( java11 之后新增 ) 

如何查看默认的垃圾收集器:

Terminal 输入命令:java -XX:+PrintCommandLineFlags -version

java -XX:+PrintCommandLineFlags -version
-XX:InitialHeapSize=267121280 
-XX:MaxHeapSize=4273940480 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC
java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.162-b12, mixed mode)

可以看到 -XX:+UseParallelGC ,即使用的是并行垃圾收集器

默认垃圾收集器有:

  • UseSerialGC
  • UseSerialOldGC(已弃用)
  • UseConcMarkSweepGC
  • UseParNewGC
  • UseParallelGC
  • UseParallelOldGC
  • UseG1GC

Java 垃圾收集器_第1张图片

     由上图可知,新生代(Young Gen)用 Serial、Parallel、ParNew这三种垃圾收集器;老年代(Old Gen)用SerialOld、ParallelOld、ConcMarkSweep这三种垃圾收集器。而G1两者都可用。

项目中如何选择垃圾收集器

  • 单 CPU 或小内存,单机程序: -XX:+UseSerialGC
  • 多 CPU ,需要大吞吐量,如后台计算型应用:-XX:+UseParallelGC 或者 -XX:+UseParallelOldGC
  • 多 CPU,追求低停顿时间,需快速响应如互联网应用:-XX:+UseConcMarkSweepGC 或者 -XX:+UseParNewGC

Java 垃圾收集器_第2张图片

如何查看当前用的是哪个垃圾收集器:

  • Terminal输入命令:jps -l ,获取进程编号
  • Terminal输入命令:jinfo -flag UseParallelGC 进程编号,输出 -XX:+UseParallelGC 说明是用的该类收集器;输出                -XX:-UseParallelGC 说明不是该类收集器。+相当于是,-相当于不是。

G1垃圾收集器

       G1-GarbageFirst 是一种服务器端的垃圾收集器,应用在多处理器和大容量内存环境中,在实现高吞吐量的同时,尽可能满足垃圾收集暂停时间的要求。另外还有以下特性:

  • 与 CMS 收集器一样,可以和应用程序并发执行
  • 整理空闲空间更快
  • 需要更多的时间来预测 GC 的停顿时间
  • 不希望牺牲大量的吞吐性能
  • 不需要大量的 Java Heap

相比之下,以前收集器的特点:

  • 年轻代和老年代是各自独立且连续的内存块
  • 年轻代收集使用单 eden+S0+S1进行复制算法
  • 老年代收集必须扫描整个老年代区域
  • 都是以尽可能少而快速的执行GC为设计原则

       CMS 收集器虽然减少了暂停应用程序的运行时间,但还是存在着内存碎片的问题,于是,为了解决内存碎片的问题,同时又保留低暂停时间的有点,Java7 就发布了一个 G1垃圾收集器

       G1 收集器的设计,目的就是为了取代 CMS 收集器,G1 与 CMS 相比,有何区别?(面试题)

  • 有整理内存过程,不会产生很多内存碎片
  • STW(Stop The World)更可控,G1 在停顿时间上添加了预测机制,让用户可以手动配置停顿时间

       G1 是在 2012年才在jdk1.7u4中可用。oracle计划在jdk9中将 G1 变成默认的垃圾收集器以替代 CMS 。它是一款面向服务端应用的收集器,主要应用在多 CPU 和大内存服务器环境下,极大减少垃圾收集的停顿时间,全面提升服务器的性能,逐步替换 java8 以前的 CMS 收集器。

主要改变是 Eden、Survivor和Tenured等内存区域不是连续的了,而是变成了一个个大小一样的 region,每个region从1M到32M不等,一个 region 可能属于 Eden、Survivor 或者 Tenured内存区域。

G1 特点总结:

  • 能充分利用多 CPU、多核环境的硬件优势,尽量缩短 STW
  • 整体上采用 “标记-压缩” 算法,局部使用 “复制” 算法,不会产生内存碎片
  • 宏观上不再区分 “老年代” 和 “新生代” ,把内存划分成独立的子区域 —Region
  • 将整个内存区域混合在一起,但其本身依然在小范围内要进行年轻代和老年代的区分,保留了新生代和老年代,但他们不再是物理隔离的,而是一部分 Region 的集合且不需要 Region是连续的,也就是说依然会采用不同的 GC 方式来处理不同区域
  • G1 虽然也是分代收集器,但整个内存区不存在物理上的年轻代和老年代的区别,也不需要完全独立的survivor(to space)堆做复制准备。G1 只有逻辑上的分代概念,或者说每一个分区都可能随 G1 的运行在不同的代之间前后切换。
  • 最大的好处是化整为零,避免全内存扫描,只需按照区域扫描。

 

 

 

你可能感兴趣的:(JVM,GC,垃圾收集器)