现在标书都从哪个网站下载,应用商店app下载安装最新版软件,网站建设阶段推广策略,网站alexa流量查询目录 学习前言
一、收集器的选择
二、GC日志参数
三、垃圾收集相关的常用参数
四、内存分配与回收策略
1. 对象优先在Eden分配
2. 大对象直接进入老年代
3. 长期存活的对象将进入老年代
4. 动态对象年龄判定
5. 空间分配担保 学习前言
本章主要学习垃圾收集器的选择及…目录 学习前言
一、收集器的选择
二、GC日志参数
三、垃圾收集相关的常用参数
四、内存分配与回收策略
1. 对象优先在Eden分配
2. 大对象直接进入老年代
3. 长期存活的对象将进入老年代
4. 动态对象年龄判定
5. 空间分配担保 学习前言
本章主要学习垃圾收集器的选择及相关参数
在实际生产环境上应该如何选择垃圾收集器相关参数如何设置
这里只考虑OpenJDK/OracleJDK的HotSpot虚拟机上的垃圾收集器。
没有将Azul和OpenJ9的垃圾收集器加入选择范围因为不了解。
一、收集器的选择
考虑垃圾收集器的选择时需要考虑以下事项
对于不可能三角(内存占用/吞吐量/延迟)应用的主要功能更关注什么比如一个OLAP系统它的大部分功能是各种数据分析和运算目标是尽快完成计算任务给出结果那么吞吐量就是主要关注点。而一个OLTP系统它需要与用户频繁交互用户频繁地通过页面操作录入数据那么延迟就是主要关注点。而如果是一个客户端应用或者嵌入式应用那么内存占用就是主要关注点。应用运行的基础设施如何包括但不限于CPU核数内存大小操作系统是Linux还是Windows等等。使用的JDK是什么版本9之前还是9以后
简单列一个表格可以参考该表格选择垃圾收集器 垃圾收集器 关注点 硬件资源 操作系统 JDK版本 优势 劣势 ZGC 低延迟 大内存很多核 64位操作系统 JDK15以上 延迟真低 需要足够的JVM调试能力;不分代连续高湾大量内存分配时只能增加堆内存。 Shenandoah 低延迟 大内存很多核 - openJDK15以上 延迟很低 需要足够的JNM调试能力;没有ZGC延迅低。 G1 低延迟 4G以上内存多核 - JDK9以上 延迟相对较低技术成熟 内存占用相对其他经典GC较多延迟低延迟GC受高: ParNew*CMS 低延迟 4G以下内存多核 - JDK9之前 延迟相对较低技术成熟 已经被抛弃更大的堆内存比不上G1 Parallel(Scavenge*Old) 吞吐量 - - - 吞吐量高 延迟较高 Serial*Serial Old 内存占用 - - - 内存占用低CPU负荷低 延迟高香吐低
简单总结一下就是主流的就做一个普通的JavaWeb或者微服务中的后台服务
与用户交互较多那就根据Java版本来不是 G1 就是 ParNewCMS
Java版本在9及9以上那就无脑选择G1默认即可Java版本还是8甚至更老那就ParNewCMS
有点追求的根据情况来
有足够的JVM调优能力且对低延迟有追求可以尝试ZGC或Shenandoah主要做后台单纯数据运算的比如OLAP可以尝试Parallel(ScavengeOld)C/S架构的客户端应用或者嵌入式应用可以尝试 SerialSerail Old。
二、GC日志参数
Java9之前HotSpot没有统一日志框架参数比较混乱Java9之后所有日志功能都归纳到了 -
Xlog 参数上。
Java9的JVM日志使用方式
-Xlog[:[selector][:[output][:[decorators][:output-options]]]]
说明
selector选择器由标签tag和日志级别level组成。标签是功能模块它指定输出哪个功能模块的日志GC日志的话标签就是gc日志级别从低到高有Trace、Debug、Info、Warning、Error、Off。decorators修饰器指定每行日志的额外输出内容包括time当前时间戳uptimeVM启动到现在的秒数timemillis当前时间毫秒数uptimemillisVM启动到现在的毫秒数timenanos当前时间纳秒数uptimenanosVM启动到现在的纳秒数pid进程IDtid线程IDlevel日志级别tags日志标签。默认是uptime、level和tags。
参考Java9前后GC相关日志参数对比 功能 Java9及之后 Java9之前 查看GC基本信息 -Xlog;gc -XX:PrintGC 查看GC详细信息 -X-log:gc* -XX:PrintGCDetails 查看GC前后空间变化 -Xlog:gcheapdebug -XX:PrintHeapAtGC 查看GC中并发时间和停顿时 间 -Xlog:safepoint -XX:Print-GCApplicationConcurrentTime 和 -XX:PrintGcApplicationstoppedTime 查看GC自适应调节信息 -Xlog:gcergo*trace -XX:PrintAdaptive-SizePolicy 查看GC后剩余对象年龄分布 -Xlog:gcagetrace -XX:PrintTenuring-Distribution
还有一个 -verbose:gc 参数功能与 -Xlog:gc 以及 -XX:PrintGC 一样。
Java8的 GC 日志的查看请参考以前的文章:
java8添加并查看GC日志(ParNewCMS)
三、垃圾收集相关的常用参数 四、内存分配与回收策略
Java技术体系的自动内存管理最根本的目标是自动化地解决两个问题自动给对象分配内存以及
自动回收分配给对象的内存。
1. 对象优先在Eden分配
大多数情况下对象在新生代·Eden区中分配。
当Eden区没有足够空间进行分配时虚拟机将发起 一次Minor GC。
HotSpot虚拟机提供了-XXPrintGCDetails这个收集器日志参数告诉虚拟机在发生垃圾收集行
为时打印内存回收日志并且在进程退出的时候输出当前的内存各区域分配情况。
2. 大对象直接进入老年代
大对象就是指需要大量连续内存空间的Java对象最典型的大对象便是那种很长的字符串或者元
素数量很庞大的数组例如创建一个典型的大对象byte[]数组。
在Java虚拟机中要避免大对象的原因是在分配空间时它容易 导致内存明明还有不少空间时就
提前触发垃圾收集以获取足够的连续空间才能安置好它们而当复制对象时大对象就意味着高
额的内存复制开销。
HotSpot虚拟机提供了-XXPretenureSizeThreshold参数指定大于该设置值的对象直接在老年代
分配这样做的目的就是避免在Eden区及两个Survivor区 之间来回复制产生大量的内存复制操
作。
-XXPretenureSizeThreshold参数只对Serial和ParNew两款新生代收集器有效HotSpot的其他
新生代收集器如Parallel Scavenge并不支持这个参数如果必须使用此参数进行调优可考虑
ParNew加CMS的收集器组合。
3. 长期存活的对象将进入老年代
HotSpot虚拟机中多数收集器都采用了分代收集来管理堆内存那内存回收时就必须能决策哪些存
活对象应当放在新生代哪些存活对象放在老年代中为做到这点虚拟机给每个对象定义了一个
对象年龄Age计数器存储在对象头中。
对象通常在Eden区里诞生如果经过第一次Minor GC后仍然存活并且能被Survivor容纳的话
该对象会被移动到Survivor空间中并且将其对象年龄设为1岁对象在Survivor区中每熬过一次
Minor GC年龄就增加1岁当它的年龄增加到一定程 度默认为15就会被晋升到老年代
中。
对象晋升老年代的年龄阈值可以通过参数-XXMaxTenuringThreshold设置。
4. 动态对象年龄判定
为了能更好地适应不同程序的内存状况HotSpot虚拟机并不是永远要求对象的年龄必须达到XX
MaxTenuringThreshold才能晋升老年代如果在Survivor空间中相同年龄所有对象大小的总和大于
Survivor空间的一半年龄大于或等于该年龄的对象就可以直接进入老年代无须等到-XX
MaxTenuringThreshold中要求的年龄。
5. 空间分配担保
在发生Minor GC之前虚拟机必须先检查老年代最大可用的连续空间是否大于新生代所有对象总
空间如果这个条件成立那这一次Minor GC可以确保是安全的如果不成立则虚拟机会先查
看XX
HandlePromotionFailure参数的设置值是否允许担保失败Handle Promotion Failure如果允
许那会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小
如果大于将尝试进行一次Minor GC尽管这次Minor GC是有风险的如果小于或者-XX
HandlePromotionFailure设置不允许冒险那这时就要改为进行一次Full GC。
“冒险”是冒了什么风险前面提到过新生代使用复制收集算法但为了内存利用率 只使用其中
一个Survivor空间来作为轮换备份因此当出现大量对象在Minor GC后仍然存活的情况最极端的
情况就是内存回收后新生代中所有对象都存活需要老年代进行分配担保把Survivor无 法容纳的
对象直接送入老年代这与生活中贷款担保类似。
老年代要进行这样的担保前提是老年代 本身还有容纳这些对象的剩余空间但一共有多少对象
会在这次回收中活下来在实际完成内存回收之 前是无法明确知道的所以只能取之前每一次回收
晋升到老年代对象容量的平均大小作为经验值与 老年代的剩余空间进行比较决定是否进行Full
GC来让老年代腾出更多空间。
取历史平均值来比较其实仍然是一种赌概率的解决办法也就是说假如某次Minor GC存活后的对
象突增远远高于历史平均值的话依然会导致担保失败。如果出现了担保失败那就只好老老实
实 地重新发起一次Full GC这样停顿时间就很长了。
虽然担保失败时绕的圈子是最大的但通常情况下 都还是会将-XXHandlePromotionFailure开关
打开避免Full GC过于频繁。