HotSpot 虚拟机垃圾收集器调优指南三

3 垃圾收集器的实现

Java SE 平台的一个优点是,它使开发人员免受复杂的内存分配和垃圾收集的困扰。
然而,当垃圾收集成为妨碍性能提升的主要瓶颈时,了解其实现的某些方面是很有用的。
主题

  • 分代垃圾回收
  • 分代
  • 性能考虑
  • 吞吐量和占用空间测量

分代垃圾回收
当运行程序中任何其他活动对象的引用不能再访问它时,一个对象被认为是垃圾并且它的内存可以被VM重用。
理论上,最直接的垃圾收集算法在每次运行时遍历每个可达对象。任何剩余的对象都被认为是垃圾。这种方法所花费的时间与活动对象的数量成正比,这对于维护大量存活数据的大型应用程序来说是不可取的。

Java HotSpot VM集成了许多不同的垃圾回收算法,除了ZGC之外,所有这些算法都使用一种称为分代回收的技术。不成熟的垃圾回收每次都会 检查堆中的每个活动对象,而分代垃圾回收利用大多数应用程序的几个经验观察属性,以最小化回收(垃圾)对象所需的工作。在这些观察到的特性中,最重要的就是弱代假说,该假设认为大多数对象只能存活很短。
图3-1的蓝色区域是对象生命周期的典型分布。x轴以分配的字节为单位显示对象生命周期,y轴上的字节数是具有相应生命周期的对象的总字节数。左边的尖峰表示在分配后不久可以回收(换句话说,已经“死亡”)的对象。例如,迭代器对象通常只在单个循环期间有效。
在这里插入图片描述
一些对象存活时间长,所以分布向右延伸。例如,通常有一些初始化时分配的对象一直存在到VM退出。在这两个极端之间是存在于某些中间计算期间的对象,在这里被视为初始峰值右侧的块。高效的回收是通过关注大多数对象“存活不久”这一事实而实现的。

分代
为了针对此场景进行优化,内存按代管理(存储不同年龄对象的内存池),垃圾回收发生在每一代填满时。
绝大多数对象分配在年轻代,并且大多数对象在年轻代死亡。当年轻代填满时,会导致一个次要的垃圾回收(minor GC)其中只收集年轻代。其他代的垃圾不会被回收。这种收集的成本首先与收集的活动对象的数量成正比。充满死对象的年轻代会很快被回收。通常,在每次minor GC期间,年轻代中一部分幸存对象会被移动到老年代。最终,老年代被填满必须被回收,导致Major GC,在Major GC 中,整个堆被回收。Major GC 通常比Minor GC持续的时间长得多,因为涉及的对象的数量要多得多。

图3-2显示了串行垃圾收集器中默认的代的排列:
在这里插入图片描述
在启动时,**Java HotSpot VM **在地址空间中保留整个Java堆,但不为它分配任何物理内存直到需要。覆盖Java堆整个地址空间逻辑上被分成了年轻代和老年代。
年轻代有Eden区和两个survivor区组成。大多数对象最初是在Eden区中分配的。其中一个survivor区总是空的,在垃圾收集期间充当在Eden区和另一个survivor区存活对象的目的地。在垃圾回收之后,Eden和其中一个Survivor区都是空的。在下一次垃圾回收中,两个survivor区的用途交换。最近填充的一个空间是存活对象的来源,这些对象被复制到另一个Survivor区。以这种方式在Survivor区之间复制对象,直到已经被复制了相当多的次数或者已经没有剩余空间。然后这些对象将被复制到年老代中,这个过程也被称为老化。

性能考虑
垃圾回收的主要度量标准是吞吐量和延迟。

  • 吞吐量是在很长一段时间内不用于垃圾收集时间的百分比。吞吐量包括分配所花费的时间。
  • 延迟是应用程序的响应能力,垃圾回收会影响应用程序的响应时间。

用户对于垃圾回收有不同的需求。例如,一些人认为对web服务器的评判标准是吞吐量,因为他们认为垃圾回收期间的暂停有可能是能容忍的或者只是被网络延迟给覆盖了。然而,在交互式图形程序中,即使是很短的暂停也可能对用户体验产生负面影响。

有些用户对其其他考虑很敏感。内存占用是进程的工作集,以页面和缓存行为单位进行度量。在物理内存有限或进程众多的系统上,内存占用可能决定了可伸缩性。
及时性是指对象失效和内存可用之间的时间间隔。这是包括远程方法调用(RMI)在内的分布式系统一个重要考虑因素。
总的来说,为特定代选择大小是这些考虑之间的权衡。例如,一个非常大的年轻代可能会导致大吞吐量,这是以占用空间,及时性以及暂停时间为代价的。
年轻代暂停时间可以通过以牺牲吞吐量为代价使用小的年轻代来最小化。一代的大小调整是不会影响另一代的垃圾回收频率和暂停时间的。
没有一种正确的方法来选择某一代的大小。最佳选择取决于应用程序使用内存的方式和用户需求。因此,虚拟机对垃圾回收器的选择并不总是最优的,可能会被命令行参数覆盖。

吞吐量和内存占用测量

例如,可以使用客户机负载生成器测试web服务器的吞吐量。但是,通过检查虚拟机本身的诊断输出,可以很容易的估计由垃圾收集引起的暂停。命令行参数-verbose:gc在每次回收的时候打印关于堆和垃圾收集的信息。如下:

[15,651s][info ][gc] GC(36) Pause Young (G1 Evacuation Pause) 239M->57M(307M) (15,646s, 15,651s) 5,048ms
[16,162s][info ][gc] GC(37) Pause Young (G1 Evacuation Pause) 238M->57M(307M) (16,146s, 16,162s) 16,565ms
[16,367s][info ][gc] GC(38) Pause Full (System.gc()) 69M->31M(104M) (16,202s, 16,367s) 164,581ms

输出显示了两个年轻代收集,随后跟着一个FULL GC,该收集由应用程序调用System.gc()发起。这些行以一个时间戳开始,表示应用程序启动的时间。接下来是关于这一行的日志级别(info)和标记(GC)信息。紧跟着后面是一个GC标识号。在本例中,有三个GC,编号为36,37和38.然后记录GC的类型和说明GC的原因。在此之后,记录有关内存消耗的一些信息。该日志使用的格式为“GC之前使用大小” -> “GC之后使用大小”(“堆大小”)。
在示例的第一行中,这是239M—>57M(307M),这意味着在GC之前使用的239MB,并且GC清除了大部分内存,但保留了57MB。堆的大小为307MB。注意,在本例中,FULL GC 将堆从307MB缩小到104MB。在内存使用信息之后,记录GC的开始和结束时间以及持续时间(end-start)。
这个-verbose:gc 命令是-Xlog:gc的别名。-Xlog是在HotSpot JVM 中进行日志记录的通用配置参数。要获得关于GC正在做什么的更多信息,可以配置日志记录打印具有GC标记和任何其他标记的任何消息。为此的命令行参数是:-Xlog:gc*。
下面是一个使用-Xlog:gc*记录的G1年轻代收集的示例:

[10.178s][info][gc,start ] GC(36) Pause Young (G1 Evacuation Pause) 
[10.178s][info][gc,task ] GC(36) Using 28 workers of 28 for evacuation 
[10.191s][info][gc,phases ] GC(36) Pre Evacuate Collection Set: 0.0ms
[10.191s][info][gc,phases ] GC(36) Evacuate Collection Set: 6.9ms 
[10.191s][info][gc,phases ] GC(36) Post Evacuate Collection Set: 5.9ms 
[10.191s][info][gc,phases ] GC(36) Other: 0.2ms 
[10.191s][info][gc,heap ] GC(36) Eden regions: 286->0(276) 
[10.191s][info][gc,heap ] GC(36) Survivor regions: 15->26(38)
[10.191s][info][gc,heap ] GC(36) Old regions: 88->88 
[10.191s][info][gc,heap ] GC(36) Humongous regions: 3->1 
[10.191s][info][gc,metaspace ] GC(36) Metaspace: 8152K->8152K(1056768K)
[10.191s][info][gc ] GC(36) Pause Young (G1 Evacuation Pause) 391M->114M(508M) 13.075ms 
[10.191s][info][gc,cpu ] GC(36) User=0.20s Sys=0.00s Real=0.01s

注: -Xlog:gc*生成的输出格式可能会在以后的版本中更改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值