共计 6640 个字符,预计需要花费 17 分钟才能阅读完成。
JVM 参数降级提醒工具:jacoline.dev/inspect
JVM 参数词典:chriswhocodes.com
Revolut(英国领取巨头)降级 Java 17 实战:https://www.bilibili.com/vide…
目前失常微服务综合内存占用 + 提早 + 吞吐量,还是 G1 更优良。然而如果你的微服务自身压力没到机器极限,要求提早低,那么 ZGC 最好。如果你是实现数据库那样的需要(大量缓存对象,即长时间生存对象,老年代很大,并且还会可能调配大于区域的对象),那么必须应用 ZGC。
应用 G1GC 启动参数:
-XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-OmitStackTraceInFastThrow -Xlog:gc*=debug:file=${LOG_PATH}/gc%t.log:utctime,level,tags:filecount=50,filesize=100M -Xlog:jit+compilation=info:file=${LOG_PATH}/jit_compile%t.log:utctime,level,tags:filecount=10,filesize=10M -Xlog:safepoint=debug:file=${LOG_PATH}/safepoint%t.log:utctime,level,tags:filecount=10,filesize=10M -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Dnetworkaddress.cache.ttl=10 -Xms2048m -Xmx2048m -Xmn1280m -Xss512k -XX:MaxDirectMemorySize=1024m -XX:MetaspaceSize=384m -XX:ReservedCodeCacheSize=256m -XX:+DisableExplicitGC -XX:MaxGCPauseMillis=50 -XX:-UseBiasedLocking -XX:GuaranteedSafepointInterval=0 -XX:+UseCountedLoopSafepoints -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=1000 -XX:StartFlightRecording=disk=true,maxsize=4096m,maxage=3d -XX:FlightRecorderOptions=maxchunksize=128m --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED
应用 ZGC 启动参数:
-XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:-OmitStackTraceInFastThrow -Xlog:gc*=debug:file=${LOG_PATH}/gc%t.log:utctime,level,tags:filecount=50,filesize=100M -Xlog:jit+compilation=info:file=${LOG_PATH}/jit_compile%t.log:utctime,level,tags:filecount=10,filesize=10M -Xlog:safepoint=debug:file=${LOG_PATH}/safepoint%t.log:utctime,level,tags:filecount=10,filesize=10M -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom -Dnetworkaddress.cache.ttl=10 -Xms2048m -Xmx2048m -Xmn1280m -Xss512k -XX:MaxDirectMemorySize=1024m -XX:MetaspaceSize=384m -XX:ReservedCodeCacheSize=256m -XX:+DisableExplicitGC -XX:+UseZGC -XX:-UseBiasedLocking -XX:GuaranteedSafepointInterval=0 -XX:+UseCountedLoopSafepoints -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=1000 -XX:StartFlightRecording=disk=true,maxsize=4096m,maxage=3d -XX:FlightRecorderOptions=maxchunksize=128m --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED
其中,须要做成环境变量内部能够配置的是:
-Xms2048m -Xmx2048m -Xmn1280m -Xss512k -XX:MaxDirectMemorySize=1024m -XX:MetaspaceSize=384m -XX:ReservedCodeCacheSize=256m
外面的参数-XX:StartFlightRecording=disk=true,maxsize=4096m,maxage=3d
其中的 4096m 以及 3d-XX:MaxGCPauseMillis=50
:这个只有应用 G1GC 的须要
JVM 日志相干:
JVM 日志配置请参考:https://zhuanlan.zhihu.com/p/…
- 须要异步输入日志,避免卡死 JVM:
-Xlog:async
- GC 日志:
-Xlog:gc*=debug:file=${LOG_PATH}/gc%t.log:utctime,level,tags:filecount=50,filesize=100M
- JIT 编译日志:
-Xlog:jit+compilation=info:file=${LOG_PATH}/jit_compile%t.log:utctime,level,tags:filecount=10,filesize=10M
- Safepoint 日志:
-Xlog:safepoint=debug:file=${LOG_PATH}/safepoint%t.log:utctime,level,tags:filecount=10,filesize=10M
- 敞开堆栈省略:这个只会省略 JDK 外部的异样,比方 NullPointerException 这种的:
-XX:-OmitStackTraceInFastThrow
,咱们利用曾经对于大量报错的时候输入大量堆栈导致性能压力的优化,参考:https://zhuanlan.zhihu.com/p/…
零碎属性 (环境变量) 启动参数:
-Dfile.encoding=UTF-8
:指定编码为 UTF-8,其实 Java 18 之后默认编码就是 UTF-8 了,这样防止不同操作系统编译带来的差别(Windows 默认是 GB2312,Linux 默认是 UTF-8),参考:https://openjdk.java.net/jeps…-Djava.security.egd=file:/dev/./urandom
:更换 random 为 urandom 防止高并发加密证书通信的时候的生成随机数带来的阻塞(例如高并发 https 申请,高并发 mysql 连贯通信),参考:https://zhuanlan.zhihu.com/p/…-Dnetworkaddress.cache.ttl=10
:将 DNS 缓存升高为 10s 过期,咱们 k8s 外部有很多通过域名解析的资源(通过 k8s 的 coreDNS),解析的 ip 可能会过期,漂移成新的 ip,默认的 30s 有点久,改成 10s,然而这会减少 coreDNS 的压力。
内存管制相干:
以下须要做成能够在内部配置的环境变量:
- 堆内存管制:
-Xms2048m -Xmx2048m -Xmn1280m
- 线程栈大小管制:
-Xss512k
- 间接内存(各种 Direct Buffer)大小管制:
-XX:MaxDirectMemorySize=1024m
- 元空间管制:
-XX:MetaspaceSize=384m
- JIT 即时编译后(C1 C2 编译器优化)的代码占用内存:
-XX:ReservedCodeCacheSize=256m
除了以上内存,JVM 还有其余内存占用,无奈通过显示的配置限度,参考:https://www.zhihu.com/questio…
GC 管制相干:
通用参数:
-XX:+DisableExplicitGC
:敞开显示 GC(System.gc()触发的 FullGC),避免 netty 这种误检测内存透露显示调用
G1GC 参数:
Java 9 之后默认 GC 就是 G1GC,所以不必显示指定应用 G1GC
在 Java 14 之后 G1GC 有微小冲破,目前 Java 17 中曾经不须要调非常复杂的参数了,能够只调整指标最大 STW(Stop-the-world)工夫来平衡 CPU 占用,内存占用与提早。
-XX:MaxGCPauseMillis=50
:指标最大 STW(Stop-the-world)工夫,这个越小,GC 占用 CPU 资源,占用内存资源就越多,微服务吞吐量就越小,然而提早低。这个须要做成可配置的
ZGC 参数:
ZGC 不必调优,是自适应的
-XX:+UseZGC
:应用 ZGC
平安点管制
对于平安点,能够查看这篇文章:https://zhuanlan.zhihu.com/p/…
-XX:-UseBiasedLocking
:禁用偏差锁,偏差锁其实将来会被齐全移除(参考:),目前咱们都是高并发的环境,偏差锁根本没啥用并且还有负面影响-XX:GuaranteedSafepointInterval=0
:禁用定时平安点工作,没必要,咱们不是那种热点代码常常扭转,资源宝贵的场景,并且如果是 ZGC 自身就会定时进入平安点进行 GC 查看,更没必要了-XX:+UseCountedLoopSafepoints
:避免大有界循环带来的迟迟不进入平安点导致 GC STW 工夫过长-XX:+SafepointTimeout -XX:SafepointTimeoutDelay=1000
:避免其余状况下导致进入平安点工夫过长导致 STW 工夫过长,这里配置的是 1s。然而没有指定 AbortVMOnSafepointTimeout 为 true,所以对你的 jmap 以及 jstack 命令没有影响
JFR 配置
JFR 应用请参考:https://zhuanlan.zhihu.com/p/…
-XX:StartFlightRecording=disk=true,maxsize=4096m,maxage=3d -XX:FlightRecorderOptions=maxchunksize=128m
模块化限度
--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.net=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.base/java.time=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/jdk.internal.access=ALL-UNNAMED --add-opens java.base/jdk.internal.misc=ALL-UNNAMED
Java 16 将 --illegal-access
的默认值从 permit 改成了 deny (JEP: https://openjdk.java.net/jeps…),Java 17 间接移除了这个选项 (JEP: https://openjdk.java.net/jeps…),所以当初要突破模块化封装,必须通过这个命令具体突破某些模块向某些模块的裸露。这里蕴含了一些罕用的可能会被反射拜访的 java.base 下的 package,向所有未命名模块裸露(咱们本人的我的项目个别不会指定模块名,如果你指定了就换成具体你的模块名)
这个也能从上面的报错中看出:
Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @7586beff
当初启动参数配置有点简单,没法指定某个模块下的所有包都向某个模块裸露,并且将来也没有这个打算,参考:https://jigsaw-dev.openjdk.ja…
微信搜寻“干货满满张哈希”关注公众号,加作者微信,每日一刷,轻松晋升技术,斩获各种 offer:
我会常常发一些很好的各种框架的官网社区的新闻视频材料并加上集体翻译字幕到如下地址(也包含下面的公众号),欢送关注:
- 知乎:https://www.zhihu.com/people/…
- B 站:https://space.bilibili.com/31…