垃圾回收调整简介

从桌面上的小程序到大型服务器上的 Web 服务,各种各样的应用程序都使用 Java 平台标准版 (Java SE)。为了支持这种多样化的部署,Java HotSpot VM 提供了多个垃圾回收器,每个垃圾回收器都旨在满足不同的需求。Java SE 根据运行应用程序的计算机的类选择最合适的垃圾回收器。但是,这种选择可能并非适合每个应用。具有严格性能目标或其他要求的用户、开发人员和管理员可能需要显式选择垃圾回收器并调整某些参数以实现所需的性能级别。本文档提供的信息可帮助完成这些任务。

首先,垃圾回收器的一般功能和基本调优选项在串行停止世界回收器的上下文中描述。然后介绍其他收集器的具体特征以及选择收集器时要考虑的因素。

什么是垃圾回收器?

垃圾回收器 (GC) 自动管理应用程序的动态内存分配请求。

垃圾回收器通过以下操作执行自动动态内存管理:

  • 从操作系统分配内存并将其返回给操作系统。
  • 在应用程序请求时将该内存分发给应用程序。
  • 确定应用程序仍在使用该内存的哪些部分。
  • 回收未使用的内存以供应用程序重用。

Java HotSpot 垃圾回收器采用各种技术来提高这些操作的效率:

  • 将分代清理与老化结合使用,将精力集中在堆中最有可能包含大量可回收内存区域的区域上。
  • 使用多个线程主动使操作并行,或在应用程序并发的后台执行一些长时间运行的操作。
  • 尝试通过压缩活动对象来恢复更大的连续可用内存。

为什么垃圾收集器的选择很重要?

垃圾回收器的目的是将应用程序开发人员从手动动态内存管理中解放出来。开发人员无需将分配与解除分配相匹配,并密切注意分配的动态内存的生存期。这完全消除了与内存管理相关的某些类别的错误,但代价是一些额外的运行时开销。Java HotSpot VM 提供了一系列垃圾回收算法供您选择。

垃圾回收器的选择何时重要?对于某些应用程序,答案是永远不会。也就是说,应用程序在存在垃圾回收的情况下可以很好地执行,暂停频率和持续时间适中。但是,对于大型应用程序而言,情况并非如此,尤其是那些具有大量数据(数千兆字节)、许多线程和高事务速率的应用程序。

阿姆达尔定律(给定问题中的并行加速受问题的顺序部分的限制)意味着大多数工作负载无法完美并行化;某些部分始终是顺序的,不会从并行性中受益。在 Java 平台中,目前有四种受支持的垃圾回收替代方案,除了其中一种(串行 GC)之外,其他所有替代方案都并行化工作以提高性能。尽可能降低垃圾回收的开销非常重要。这可以在以下示例中看到。

图 1-1 中的图形模拟了一个理想的系统,该系统可完全扩展,但垃圾回收除外。红线表示应用程序在单处理器系统上仅花费 1% 的时间进行垃圾回收。这意味着在具有 32 个处理器的系统上,吞吐量损失超过 20%。洋红色行显示,对于垃圾回收中 10% 时间的应用程序(在单处理器应用程序中的垃圾回收中不被认为是异常时间),当扩展到 32 个处理器时,吞吐量会丢失 75% 以上。

图 1-1 比较垃圾回收所花费的时间百分比

“图 1-1 比较垃圾回收所花费时间的百分比”的说明

此图显示,在小型系统上开发时可以忽略不计的吞吐量问题在扩展到大型系统时可能成为主要瓶颈。但是,在减少此类瓶颈方面的小改进可以带来巨大的性能提升。对于足够大的系统,选择正确的垃圾收集器并在必要时对其进行调整变得值得。

串行收集器通常足以满足大多数小型应用程序,特别是那些在现代处理器上需要高达大约 100 MB 的堆的应用程序。其他收集器具有额外的开销或复杂性,这是专用行为的代价。如果应用程序不需要备用收集器的专用行为,请使用串行收集器。串行收集器不应成为最佳选择的一种情况是在具有大量内存和两个或更多处理器的计算机上运行的大型重线程应用程序。在此类服务器级计算机上运行应用程序时,默认情况下会选择垃圾优先 (G1) 收集器;

 垃圾器算法的择优是Java 虚拟机 (JVM) 和垃圾回收启发式(如基于行为的启发式)提高应用程序性能的过程。

JVM 为垃圾回收器、堆大小和运行时编译器提供了依赖于平台的缺省选择。这些选择符合不同类型应用程序的需求,同时需要较少的命令行调整。此外,基于行为的调优可动态优化堆的大小,以满足应用程序的指定行为。

后面章节介绍这些默认选择和基于行为的优化结果。

垃圾回收器、堆和运行时编译器默认选择

这些是重要的垃圾回收器、堆大小和运行时编译器默认选择:

  • 垃圾优先 (G1) 收集器
  • GC 线程的最大数量受堆大小和可用 CPU 资源的限制
  • 初始堆大小为物理内存的 1/64
  • 最大堆大小为物理内存的 1/4
  • 分层编译器,同时使用 C1 和 C2

基于行为的调优

可以将 Java HotSpot VM 垃圾回收器配置为优先满足以下两个目标之一:最大暂停时间和应用程序吞吐量。如果满足了首选目标,收集者将尝试最大化另一个目标。当然,这些目标并不总是可以满足的:应用程序需要最少的堆来保存至少所有实时数据,而其他配置可能会阻止实现部分或全部所需目标。

最大暂停时间目标

暂停时间是垃圾回收器停止应用程序并恢复不再使用的空间的持续时间。最大暂停时间目标的目的是限制这些暂停中的最长时间。

暂停的平均时间和该平均值的差异由垃圾回收器维护。平均值是从执行开始开始的,但它是加权的,以便最近的暂停计数更多。如果暂停时间的平均值加上方差大于最大暂停时间目标,则垃圾回收器认为未达到目标。

最大暂停时间目标使用命令行选项 <nnn> 指定。这被解释为向垃圾回收器提示需要 <nnn> 毫秒或更短的暂停时间。垃圾回收器调整 Java 堆大小以及与垃圾回收相关的其他参数,以尝试使垃圾回收暂停时间短于 <nnn> 毫秒。最大暂停时间目标的默认值因收集器而异。这些调整可能会导致垃圾回收更频繁地发生,从而降低应用程序的总体吞吐量。但是,在某些情况下,无法实现所需的暂停时间目标。-XX:MaxGCPauseMillis=

吞吐量目标

吞吐量目标根据收集垃圾所花费的时间来衡量,在垃圾收集之外花费的时间是应用程序时间。

目标由命令行选项 nnn 指定。垃圾回收时间与申请时间之比为 1/ (1+nnn)。例如,将目标设置为垃圾回收总时间的 1/20 或 5%。-XX:GCTimeRatio=-XX:GCTimeRatio=19

垃圾回收所花费的时间是所有垃圾回收引起的暂停的总时间。如果未达到吞吐量目标,则垃圾回收器的一个可能操作是增加堆的大小,以便收集暂停之间在应用程序中花费的时间可以更长。

Footprint

如果已达到吞吐量和最大暂停时间目标,则垃圾回收器会减小堆的大小,直到无法满足其中一个目标(始终是吞吐量目标)。垃圾回收器可以使用的最小和最大堆大小,可以分别使用-Xms=<nnn>、-Xmx=<mmm> 来设置。

调优策略

堆增长或收缩到支持所选吞吐量目标的大小。了解堆优化策略,例如选择最大堆大小和选择最大暂停时间目标。

不要为堆选择最大值,除非您知道需要大于默认最大堆大小的堆。选择足以满足应用程序的吞吐量目标。

应用程序行为的更改可能会导致堆增大或增大。例如,如果应用程序开始以更高的速率进行分配,则堆会增长以保持相同的吞吐量。

如果堆增长到其最大大小,但未达到吞吐量目标,则最大堆大小对于吞吐量目标来说太小。将最大堆大小设置为接近平台上的总物理内存的值,但不会导致应用程序交换。再次执行应用程序。如果仍未达到吞吐量目标,则应用程序时间的目标对于平台上的可用内存来说太高。

如果可以达到吞吐量目标,但暂停时间过长,请选择最大暂停时间目标。选择最大暂停时间目标可能意味着无法满足吞吐量目标,因此请选择应用程序可接受的折衷值。

通常,当垃圾回收器尝试满足竞争目标时,堆的大小会波动。即使应用程序已达到稳定状态,也是如此。实现吞吐量目标(可能需要更大的堆)的压力与最大暂停时间和最小占用空间(两者都可能需要一个小堆)的目标竞争。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2018-09-04,如有侵权请联系 cloudcommunity@tencent 删除java教程垃圾回收内存系统