一、最佳实践参数

直入主题,先给上最佳实践的参数配置

ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:InitialRAMPercentage=75.0 -XX:MinRAMPercentage=75.0 -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/appuser/gc.hprof -Djava.io.tmpdir=/home/appuser/java_tmp -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseBiasedLocking -XX:+DisableExplicitGC -XX:+UseFastAccessorMethods"

二、容器上面的 JVM 有何特殊

登录容器服务,我们执行 top free 命令查看到的 cpu、内存都不是容器的正确资源,这些命令显示的是宿主机的资源情况。

容器的核心技术是 Cgroup + Namespace。ns 起到的是资源隔离的作用(看不到),cgroup 起的是限制资源的使用(用量不能超出),由于 ns 的隔离并不全,所以有些资源虽然看到的是这么多,但是 cgroup 却限制了不能使用这么多。

jvm 会根据系统资源帮我们初始化默认的参数配置,如果 jvm 获取到的资源数据是错误的,那么设定的 jvm 参数就会有问题。JDK 10 之后引入了默认开启的参数 UseContainerSupport 同时这个特性也被 backport 到 JDK1.8 的8u91 版本。也就是说 8u191 和更后面的 JDK 都可以通过开启 UseContainerSupport 来支持 JVM 看到 cgroup 的内存限制,再结合 MaxRAMPercentage 来动态算一个堆内存上限就足够了,这个值具体看服务用到的堆外内存和线程的使用量,一般可以给 75%,预留些资源给其它进程。

参数说明

-XX:+UseContainerSupport

可以使用-XX:+UseContainerSupport 参数来指定 JVM 使用容器内存。

-XX:MaxRAMPercentage=75.0 -XX:InitialRAMPercentage=75.0 -XX:MinRAMPercentage=75.0

这三个参数是JDK8U191为适配Docker容器新增的几个参数,类比Xmx、Xms,至于-XX:InitialRAMFraction、-XX:MaxRAMFraction、-XX:MinRAMFraction已经被标记为deprecated 。这几个参数的好处是什么呢?Docker容器模式下,我们给 JVM 设置的参数不是固定写死的,是根据一定比率的。
假设:我们给容器分配了 4G 内存,那么相当于 -Xmx3g -Xms3g,如果后面我们的容器规格扩容到 8G,那么相对于的 jvm 参数也会自动的扩容到 6g。
注意:上面的 75% 是堆内存

-XX:-UseAdaptiveSizePolicy

AdaptiveSizePolicy(自适应大小策略) 是 JVM GC Ergonomics(自适应调节策略) 的一部分。
如果开启 AdaptiveSizePolicy,则每次 GC 后会重新计算 Eden、From 和 To 区的大小,计算依据是 GC 过程中统计的 GC 时间、吞吐量、内存占用量。
开启 AdaptiveSizePolicy 的参数为: -XX:+UseAdaptiveSizePolicy JDK 1.8 默认使用 UseParallelGC 垃圾回收器,该垃圾回收器默认启动了 AdaptiveSizePolicy。

AdaptiveSizePolicy 有三个目标:

  1. Pause goal:应用达到预期的 GC 暂停时间。
  2. Throughput goal:应用达到预期的吞吐量,即应用正常运行时间 / (正常运行时间 + GC 耗时)。
  3. Minimum footprint:尽可能小的内存占用量。

AdaptiveSizePolicy 为了达到三个预期目标,涉及以下操作:

  1. 如果 GC 停顿时间超过了预期值,会减小内存大小。理论上,减小内存,可以减少垃圾标记等操作的耗时,以此达到预期停顿时间。
  2. 如果应用吞吐量小于预期,会增加内存大小。理论上,增大内存,可以降低 GC 的频率,以此达到预期吞吐量。
  3. 如果应用达到了前两个目标,则尝试减小内存,以减少内存消耗。

**注意:AdaptiveSizePolicy 涉及的内容比较广,本文主要关注 AdaptiveSizePolicy 对年轻代大小的影响,以及随之产生的问题。
AdaptiveSizePolicy 看上去很智能,但有时它也很调皮,会引发 GC 问题。**

Parallel Old 收集器

Parallel Old 收集器是Parallel Scavenge 收集器的老年代版本,使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源敏感的场合,可以优先考虑Parallel Scavenge 加 Parallel Old 收集器。
Parallel Scavenge + Parallel Old 收集
image.png

垃圾收集器小知识

# 可以看到1.8默认的是 UseParallelGC
java -XX:+PrintFlagsFinal

image.png

image.png

点赞(7) 打赏

Comment list 共有 0 条评论

暂无评论
立即
投稿
发表
评论
返回
顶部