`
zzq19860626
  • 浏览: 264478 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
B20df9e2-fb3d-3644-9f72-c1619842f682
设计模式学习笔记
浏览量:180034
87eaf24f-812a-3463-8e65-e3197d2ad8c2
java虚拟机
浏览量:26622
社区版块
存档分类
最新评论

JAVA虚拟机之四:G1垃圾收集器

阅读更多

一、关于G1

G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征. 在Oracle JDK 7 update 4 及以上版本中得到完全支持, 专为以下应用程序设计:

 

  • 可以像CMS收集器一样,GC操作与应用的线程一起并发执行 
  • 紧凑的空闲内存区间且没有很长的GC停顿时间. 
  • 需要可预测的GC暂停耗时. 
  • 不想牺牲太多吞吐量性能. 
  • 启动后不需要请求更大的Java堆. 

 

G1的长期目标是取代CMS(Concurrent Mark-Sweep Collector, 并发标记-清除). 因为特性的不同使G1成为比CMS更好的解决方案. 一个区别是,G1是一款压缩型的收集器.G1通过有效的压缩完全避免了对细微空闲内存空间的分配,不用依赖于regions,这不仅大大简化了收集器,而且还消除了潜在的内存碎片问题。除压缩以外,G1的垃圾收集停顿也比CMS容易估计,也允许用户自定义所希望的停顿参数(pause targets)。

 

 

在G1中,堆被划分成 许多个连续的区域(region)。每个区域大小相等,在1M~32M之间。JVM最多支持2000个区域,可推算G1能支持的最大内存为2000*32M=62.5G。区域(region)的大小在JVM初始化的时候决定,也可以用-XX:G1HeapReginSize设置。在G1中没有物理上的Yong(Eden/Survivor)/Old Generation,它们是逻辑的,使用一些非连续的区域(Region)组成的。这在内存使用上提供了更多的灵活性。 

 

G1执行垃圾回收的处理方式与CMS相似. G1在全局标记阶段(global marking phase)并发执行, 以确定堆内存中哪些对象是存活的。标记阶段完成后,G1就可以知道哪些heap区的empty空间最大。它会首先回收这些区,通常会得到大量的自由空间. 这也是为什么这种垃圾收集方法叫做Garbage-First(垃圾优先)的原因。顾名思义, G1将精力集中放在可能布满可收回对象的区域, 可回收对象(reclaimable objects)也就是所谓的垃圾. G1使用暂停预测模型(pause prediction model)来达到用户定义的目标暂停时间,并根据目标暂停时间来选择此次进行垃圾回收的heap区域数量.

被G1标记为适合回收的heap区将使用转移(evacuation)的方式进行垃圾回收. G1将一个或多个heap区域中的对象拷贝到其他的单个区域中,并在此过程中压缩和释放内存. 在多核CPU上转移是并行执行的(parallel on multi-processors), 这样能减少停顿时间并增加吞吐量. 因此,每次垃圾收集时, G1都会持续不断地减少碎片, 并且在用户给定的暂停时间内执行. 这比以前的方法强大了很多. CMS垃圾收集器(Concurrent Mark Sweep,并发标记清理)不进行压缩. ParallelOld 垃圾收集只对整个堆执行压缩,从而导致相当长的暂停时间。

需要强调的是, G1并不是一款实时垃圾收集器(real-time collector). 能以极高的概率在设定的目标暂停时间内完成,但不保证绝对在这个时间内完成。 基于以前收集的各种监控数据, G1会根据用户指定的目标时间来预估能回收多少个heap区. 因此,收集器有一个相当精确的heap区耗时计算模型,并根据该模型来确定在给定时间内去回收哪些heap区.

注意 G1分为两个阶段: 并发阶段(concurrent, 与应用线程一起运行, 如: 细化 refinement、标记 marking、清理 cleanup) 和 并行阶段(parallel, 多线程执行, 如: 停止所有JVM线程, stop the world). 而 FullGC(完整垃圾收集)仍然是单线程的, 但如果进行适当的调优,则应用程序应该能够避免 full GC。

G1 的内存占用(Footprint)

如果从 ParallelOldGC 或者 CMS收集器迁移到 G1, 您可能会看到JVM进程占用更多的内存(a larger JVM process size). 这在很大程度上与 “accounting” 数据结构有关, 如 Remembered Sets 和 Collection Sets.

  1. Remembered Sets 简称 RSets, 跟踪指向某个heap区内的对象引用. 堆内存中的每个区都有一个 RSet. RSet 使heap区能并行独立地进行垃圾集合. RSets的总体影响小于5%. 
  2. Collection Sets 简称 CSets, 收集集合, 在一次GC中将执行垃圾回收的heap区. GC时在CSet中的所有存活数据(live data)都会被转移(复制/移动). 集合中的heap区可以是 Eden, survivor, 和/或 old generation. CSets所占用的JVM内存小于1%. 

 

 

推荐使用 G1 的场景(Recommended Use Cases)

G1的首要目标是为需要大量内存的系统提供一个保证GC低延迟的解决方案. 也就是说堆内存在6GB及以上,稳定和可预测的暂停时间小于0.5秒.

如果应用程序具有如下的一个或多个特征,那么将垃圾收集器从CMS或ParallelOldGC切换到G1将会大大提升性能.

  • Full GC 次数太频繁或者消耗时间太长. 
  • 对象分配的频率或代数提升(promotion)显著变化. 
  • 受够了太长的垃圾回收或内存整理时间(超过0.5~1秒) 

 

注意: 如果正在使用CMS或ParallelOldGC,而应用程序的垃圾收集停顿时间并不长,那么继续使用现在的垃圾收集器是个好主意. 使用最新的JDK时并不要求切换到G1收集器。

 

二、G1 GC

1、新生代收集

G1的新生代收集跟ParNew类似,当新生代占用达到一定比例的时候,开始出发收集。

被圈起的绿色部分为新生代的区域(region),经过Young GC后存活的对象被复制到一个或者多个区域空闲中,这些被填充的区域将是新的新生代;当新生代对象的年龄(逃逸过一次Young GC年龄增加1)已经达到某个阈值(ParNew默认15),被复制到老年代的区域中。

回收过程是停顿的(STW,Stop-The-Word);回收完成之后根据Young GC的统计信息调整Eden和Survivor的大小,有助于合理利用内存,提高回收效率。回收的过程多个回收线程并发收集。

 

2、老年代收集

和CMS类似,G1收集器收集老年代对象会有短暂停顿。

  1. 标记阶段,首先初始标记(Initial-Mark),这个阶段是停顿的(Stop the World Event),并且会触发一次普通Mintor GC。对应GC log:GC pause (young) (inital-mark)
  2. Root Region Scanning,程序运行过程中会回收survivor区(存活到老年代),这一过程必须在young GC之前完成。
  3. Concurrent Marking,在整个堆中进行并发标记(和应用程序并发执行),此过程可能被young GC中断。在并发标记阶段,若发现区域对象中的所有对象都是垃圾,那个这个区域会被立即回收(图中打X)。同时,并发标记过程中,会计算每个区域的对象活性(区域中存活对象的比例)。

     
  4. Remark, 再标记,会有短暂停顿(STW)。再标记阶段是用来收集 并发标记阶段 产生新的垃圾(并发阶段和应用程序一同运行);G1中采用了比CMS更快的初始快照算法:snapshot-at-the-beginning (SATB)。
  5. Copy/Clean up,多线程清除失活对象,会有STW。G1将回收区域的存活对象拷贝到新区域,清除Remember Sets,并发清空回收区域并把它返回到空闲区域链表中。
  6. 复制/清除过程后。回收区域的活性对象已经被集中回收到深蓝色和深绿色区域。

 3、测试收集

    代码如下:

package com.tools138.com;

/**
 * 
 * @author alaric
 * 
 */
public class Test3 {

	private static int n = 20;

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub

		byte[] b1 = getM(50);
		byte[] b2 = getM(50);
		byte[] b3 = getM(50);
		byte[] b4 = getM(50);
		byte[] b5 = getM(50);
		byte[] b6 = getM(50);
		byte[] b7 = getM(5);
		byte[] b8 = getM(5);
		byte[] b9 = getM(5);
		byte[] b10 = getM(5);
		byte[] b11 = getM(5);
		byte[] b12 = getM(5);
		byte[] b13 = getM(5);
		byte[] b14 = getM(5);
		byte[] b15 = getM(5);
		byte[] b16 = getM(5);
		byte[] b17 = getM(5);
		byte[] b18 = getM(5);
		byte[] b19 = getM(5);
		byte[] b20 = getM(100);
		byte[] b21 = getM(100);
		byte[] b22 = getM(100);
		byte[] b23 = getM(100);

	}

	public static byte[] getM(int m) {
		return new byte[1024 * 1024 * m];
	}

}

 

 

 vm参数配置如下:

 

-server -verbose:gc -Xms512m -Xmx512m -Xmn192m -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=40  -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:G1HeapRegionSize=2  -Xloggc:D:/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/logs/HeapDumpOnOutOfMemoryError.log -XX:+DisableExplicitGC -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

 代码和参数配置的意思是直接让堆内存溢出,可以直接观察到G1 GC的收集过程,gc.log如下:

 

0.245: [GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0011950 secs]
   [Parallel Time: 1.0 ms, GC Workers: 4]
      [GC Worker Start (ms): Min: 245.0, Avg: 245.0, Max: 245.1, Diff: 0.0]
      [Ext Root Scanning (ms): Min: 0.3, Avg: 0.5, Max: 0.9, Diff: 0.7, Sum: 1.8]
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Object Copy (ms): Min: 0.0, Avg: 0.5, Max: 0.6, Diff: 0.6, Sum: 1.8]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
         [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 4]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 0.9, Avg: 1.0, Max: 1.0, Diff: 0.0, Sum: 3.9]
      [GC Worker End (ms): Min: 246.0, Avg: 246.0, Max: 246.0, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.0 ms]
   [Other: 0.2 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.0 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.0 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 2048.0K(192.0M)->0.0B(191.0M) Survivors: 0.0B->1024.0K Heap: 202.0M(512.0M)->200.6M(512.0M)]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
0.246: [GC concurrent-root-region-scan-start]
0.247: [GC concurrent-root-region-scan-end, 0.0006084 secs]
0.247: [GC concurrent-mark-start]
0.247: [GC concurrent-mark-end, 0.0000903 secs]
0.259: [GC remark 0.259: [Finalize Marking, 0.0000809 secs] 0.259: [GC ref-proc, 0.0000390 secs] 0.259: [Unloading, 0.0005304 secs], 0.0022501 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]
0.274: [GC cleanup 300M->300M(512M), 0.0003358 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
黑色粗体说明一个完整的老年代GC过程,蓝色代表一次新生代GC过程。一个大对象进入后,触发新生代垃圾回收,然后进入老年代,同时老年代也开始初始标记-并发根扫描-并发标记-重新标记-清除。详细的日志理解请看https://blogs.oracle.com/poonam/entry/understanding_g1_gc_logs

 

三、垃圾收集器配置参数:

Option and Default Value Description
-XX:+UseG1GC Use the Garbage First (G1) Collector
-XX:MaxGCPauseMillis=n Sets a target for the maximum GC pause time. This is a soft goal, and the JVM will make its best effort to achieve it.
-XX:InitiatingHeapOccupancyPercent=n Percentage of the (entire) heap occupancy to start a concurrent GC cycle. It is used by GCs that trigger a concurrent GC cycle based on the occupancy of the entire heap, not just one of the generations (e.g., G1). A value of 0 denotes 'do constant GC cycles'. The default value is 45.
-XX:NewRatio=n Ratio of old/new generation sizes. The default value is 2.
-XX:SurvivorRatio=n Ratio of eden/survivor space size. The default value is 8.
-XX:MaxTenuringThreshold=n Maximum value for tenuring threshold. The default value is 15.
-XX:ParallelGCThreads=n Sets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running.
-XX:ConcGCThreads=n Number of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running.
-XX:G1ReservePercent=n Sets the amount of heap that is reserved as a false ceiling to reduce the possibility of promotion failure. The default value is 10.
-XX:G1HeapRegionSize=n With G1 the Java heap is subdivided into uniformly sized regions. This sets the size of the individual sub-divisions. The default value of this parameter is determined ergonomically based upon heap size. The minimum value is 1Mb and the maximum value is 32Mb.

 

 

 

参考资料:
  • 大小: 26.5 KB
  • 大小: 45.7 KB
  • 大小: 49 KB
  • 大小: 81.9 KB
  • 大小: 46.3 KB
2
1
分享到:
评论

相关推荐

    Java理解G1垃圾收集器.pdf

    在G1收集器的工作流程中,区域可以被分为新生代(Young Generation)、老年代(Old Generation)和Survivor空间。新生代主要存放短生命周期的对象,而老年代则存放生命周期较长的对象。G1垃圾收集器会根据对象的存活...

    理解JAVA虚拟机-内存管理、垃圾收集器.pptx

    Java虚拟机(JVM)是Java程序运行的核心,它负责管理程序的内存,包括内存的分配、使用和回收。在深入理解JVM内存管理和垃圾收集器之前,我们需要先了解JVM内存模型的基本结构。 内存模型主要包括以下几个部分: 1...

    深入java虚拟机 高清pdf 高清高清高清

    《深入Java虚拟机》这本书是Java开发者深入了解JVM(Java Virtual Machine)的必备经典之作。它详尽地探讨了Java虚拟机的工作原理、内存管理、类加载机制、字节码执行以及性能优化等多个核心主题,旨在帮助开发者...

    Java虚拟机精讲.高翔龙.带书签完整版.pdf

    本书以极其精练的语句诠释了HotSpot VM 的方方面面,比如:字节码的编译原理、字节码的内部组成结构、通过源码的方式剖析HotSpot VM 的启动过程和初始化过程、Java 虚拟机的运行时内存、垃圾收集算法、垃圾收集器...

    深入理解Java虚拟机JVM高级特性与最佳实践1

    内存管理是JVM工作的一个核心部分,尤其是在垃圾收集机制方面,不同的垃圾收集器(如Serial、Parallel、CMS和G1收集器)针对不同应用场景有着各自的优化策略。书中详细介绍了这些收集器的工作原理及优缺点,为开发者...

    【深入Java虚拟机(8)】Java垃圾收集机制编程开发技

    本文将详细解析Java虚拟机(JVM)中的垃圾收集工作原理、不同类型的垃圾收集器以及如何通过编程接口进行垃圾收集的控制。 1. **垃圾收集概述** 垃圾收集(Garbage Collection, GC)是Java语言的一大特色,它自动...

    深入理解Java虚拟机笔记(带目录).docx

    * G1 垃圾收集器:低停顿的垃圾收集器。 GC 日志 GC 日志用于记录垃圾收集器的执行情况,可以用于调试和优化垃圾收集器。 内存分配 Java 中的内存分配可以分为以下几种: * 栈上分配(Stack Allocation):在栈...

    JDK19-hotspot-virtual-machine-garbage-collection-tuning-guide

    4. Garbage-First(G1)垃圾收集器:G1垃圾收集器是Java 7中引入的新型垃圾收集器,使用增量式标记-清除算法。 5. Z垃圾收集器(Z Garbage Collector):Z垃圾收集器是Java 11中引入的低延迟垃圾收集器,使用增量式...

    Java虚拟机规范(Java SE 7).pdf

    6. **垃圾收集器改进**:Java 7的垃圾收集器如G1(Garbage-First)收集器被引入,旨在减少停顿时间并提供可预测的暂停时间,适合大规模并发应用。 7. **元空间(Metaspace)替换持久代(PermGen)**:Java 7末期, ...

    G1垃圾收集器1

    **G1垃圾收集器**是Java虚拟机(JVM)的一种高效、低延迟的垃圾回收器,主要设计用于服务端的应用,特别是在多处理器和大内存环境中。G1自JDK7开始支持,其目标是在满足可预测的暂停时间的同时,保持较高的整体吞吐...

    JAVA虚拟机精讲

    《Java虚拟机精讲》以极其精练的语句诠释了HotSpot VM 的方方面面,比如:字节码的编译原理、字节码的内部组成结构、通过源码的方式剖析HotSpot VM 的启动过程和初始化过程、Java 虚拟机的运行时内存、垃圾收集算法...

    JAVA虚拟机的内存管理

    4. **G1收集器**:旨在最小化垃圾收集引起的暂停时间,同时还能实现高吞吐量,适用于大内存应用。 #### 五、HotSpot JVM的自适应优化 HotSpot JVM引入了一项新技术——**工效学(ergonomics)**,能够在不同的平台上...

    java虚拟机的两本书

    《Java虚拟机第二版》作为经典著作的更新版,通常会包含JVM的新特性和改进,比如Java SE的新版本带来的变化,如JIT(Just-In-Time)编译器的优化、G1垃圾收集器的使用、类数据共享等。这本书可能会深入到JVM的最新...

    java虚拟机学习

    G1、ZGC、Shenandoah等现代垃圾收集器提供了低延迟的内存管理。 9. 调优与监控:JVM提供了一系列的工具,如jconsole、jvisualvm、jinfo、jmap等,用于性能监控、诊断和调优。通过调整JVM参数,可以优化内存分配、...

    深入JAVA虚拟机 随书源码 JVM规范

    GC策略包括分代收集、并行GC、并发GC和G1垃圾收集器等,每种策略都有其适用场景和优缺点。通过调整GC参数,我们可以优化应用程序的内存使用和性能。 总的来说,深入了解JVM不仅能够帮助我们编写出更高效的代码,还...

    Java语言规范+Java虚拟机规范(Java8、Java9)

    1. **G1垃圾收集器的优化**:Java 8加强了G1(Garbage First)垃圾收集器,使其成为全功能的生产级垃圾回收器,适合大型应用。 2. **接口私有方法**:Java 9引入了接口私有方法,增强了接口的内部实现细节,允许...

    JAVA虚拟机性能参数调优指导书

    例如,使用-XX:+UseG1GC启用G1垃圾收集器,适用于大内存的应用场景;调整-XX:MaxGCPauseMillis以减少GC暂停时间,提高用户体验。 2. **JIT调优参数的使用**:即时编译器(JIT)将热点代码转换为本地机器码,显著...

    Java 虚拟机规范.pdf

    - 常见垃圾回收器有Serial、Parallel、CMS、G1、ZGC、Shenandoah等。 6. **JVM参数**: - JVM启动时可以通过参数对JVM进行配置,如内存大小、垃圾回收策略等。 7. **跨平台特性**: - Java的“一次编写,到处...

    基于嵌入式Java虚拟机的垃圾收集优化算法应用.pdf

    垃圾收集是Java虚拟机中的一个关键功能,它能够自动管理内存,回收不再使用的对象占用的内存空间。然而,不当的垃圾收集算法会导致应用性能降低,尤其是在内存受限的嵌入式系统中。 本论文聚焦于嵌入式Java虚拟机中...

    实战java虚拟机

    了解垃圾收集的工作原理和各种垃圾收集器,如Serial、Parallel、CMS和G1,对于优化程序性能至关重要。 再者,JVM的类加载机制也值得关注。Java的双亲委托模型确保了类加载的唯一性,防止类的重复加载。同时,我们还...

Global site tag (gtag.js) - Google Analytics