Jvm参数优化

2023-10-29

背景

假设项目每天100w次登陆请求,一个服务器节点8G内存,如何设置JVM参数?
在这里插入图片描述

1. 系统上线规划容量

- 分析

  1. 100W请求登录峰值在早上,预估峰值每秒100次登录请求
  2. 假设部署3台服务器.每台处理30次请求,假设登录请求处理需要1s,JVM新生代里每秒就要产生30个登陆对象,1s之后请求完毕的这些对象成为垃圾.
  3. 一个登陆请求对象假设20个字段,一个对象估算500字节,30个登陆佔用大约15kb,考虑到RPC和DB操作,网络通信、写库、写缓存一顿操作下来,可以扩大到20-50倍,大约1s产生几百k-1M数据。
  4. 假设2C4G机器部署,分配2G堆内存,新生代则只有几百M,按照1s1M的垃圾产生速度,几百秒就会触发一次MinorGC了
  5. 假设4C8G机器部署,分配4G堆内存,新生代分配2G,如此需要几个小时才会触发一次MinorGC。
    可以粗略的推断出来一个每天100w次请求的登录系统,按照4C8G的3实例集群配置,分配4G堆内存、2G新生代的JVM,可以保障系统的一个正常负载

2. 垃圾回收器选择

吞吐量和响应时间

吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间)
响应时间 = 平均每次的GC的耗时
通常,吞吐优先还是响应优先这个在JVM中是一个两难之选,无法同时兼顾。

垃圾回收器选择

目前主流垃圾回收器CMS或者G1
G1是官方维护和推荐的垃圾回收器
在这里插入图片描述
系统对延迟敏感的推荐CMS
系统大内存,要求高吞吐的,采用G1回收器

3. 规划各个分区的比例大小

  • 指定堆内存的大小,这是系统上线必须要做的,-Xms初始堆大小,-Xmx 最大堆大小,一般指定为系统内存的一半.
  • 指定新生代大小-Xmn,官方推荐为3/8大小,根据业务场景去区分,无状态服务一般给到堆内存的3/4大小,有状态的服务(IM,网关)堆内存的1/3大小
  • 栈内存-Xss,设置单个线程栈的大小,默认值和JDK版本有关,一般默认512-1024kb
    在这里插入图片描述
    如果采用正常的JVM参数配置如下
-Xms3072M 
-Xmx3072M 
-Xss1M 
-XX:MetaspaceSize=256M 
-XX:MaxMetaspaceSize=256M 
-XX:SurvivorRatio=8 

这样设置可能会由于动态对象年龄判断原则导致频繁full gc
压测过程中,短时间(比如20S后)Eden区就满了,此时再运行的时候对象已经无法分配,会触发MinorGC,
假设在这次GC后S1装入100M,马上过20S又会触发一次MinorGC,多出来的100M存活对象+S1区的100M已经无法顺利放入到S2区,此时就会触发JVM的动态年龄机制,将一批100M左右的对象推到老年代保存,持续运行一段时间,系统可能一个小时候内就会触发一次FullGC。
按照默认8:1:1的比例来分配时, survivor区只有 1G的 10%左右,也就是几十到100M.
将JVM参数更改为下面参数

-Xms3072M   
-Xmx3072M   
-Xmn2048M   
-Xss1M   
-XX:MetaspaceSize=256M   
-XX:MaxMetaspaceSize=256M    
-XX:SurvivorRatio=8
  • 年轻代大小2G, eden与survivor的比例1.6g:0.2g
    这样可以防止每次垃圾回收过后,survivor对象太早超过 50% ,
    就可以降低因为对象动态年龄判断原则导致的对象频繁进入老年代的问题,
    在这里插入图片描述

4. 对象年龄对少移动到老年代合适

如果对象这么长时间都没被回收,比如2分钟没有回收,可以认为这些对象是会存活的比较长的对象,从而移动到老年代,而不是继续一直占用survivor区空间。
默认值是15, 意味着对象要经过15次minor GC才会进入老年代
调整参数如下:

‐Xms3072M   
‐Xmx3072M   
‐Xmn2048M   
‐Xss1M   
‐XX:MetaspaceSize=256M   
‐XX:MaxMetaspaceSize=256M   
‐XX:SurvivorRatio=8   
‐XX:MaxTenuringThreshold=5  

5. 对象多大放到老年代

对象直接进入老年代参数-XX:PretenureSizeThreshold

‐Xms3072M   
‐Xmx3072M   
‐Xmn2048M   
‐Xss1M   
‐XX:MetaspaceSize=256M   
‐XX:MaxMetaspaceSize=256M   
‐XX:SurvivorRatio=8   
‐XX:MaxTenuringThreshold=5   
‐XX:PretenureSizeThreshold=1M 

6. 垃圾回收器CMS老年代参数优化

JDK8默认的垃圾回收器是-XX:+UseParallelGC(年轻代)和-XX:+UseParallelOldGC(老年代).
如果内存比较大,建议使用G1

‐Xms3072M   
‐Xmx3072M   
‐Xmn2048M   
‐Xss1M   
‐XX:MetaspaceSize=256M   
‐XX:MaxMetaspaceSize=256M   
‐XX:SurvivorRatio=8    
‐XX:MaxTenuringThreshold=5   
‐XX:PretenureSizeThreshold=1M   
‐XX:+UseParNewGC   
‐XX:+UseConcMarkSweepGC   
‐XX:CMSInitiatingOccupancyFraction=70   
‐XX:+UseCMSInitiatingOccupancyOnly   
‐XX:+AlwaysPreTouch 

参数说明
1.‐Xms3072M ‐Xmx3072M 最小最大堆设置为3g,最大最小设置为一致防止内存抖动
2.‐Xss1M 线程栈1m
3.‐Xmn2048M ‐XX:SurvivorRatio=8 年轻代大小2g,eden与survivor的比例为8:1:1,也就是1.6g:0.2g:0.2g
4.-XX:MaxTenuringThreshold=5 年龄为5进入老年代 5.‐XX:PretenureSizeThreshold=1M 大于1m的大对象直接在老年代生成
6.‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC 使用ParNew+cms垃圾回收器组合
7.‐XX:CMSInitiatingOccupancyFraction=70 老年代中对象达到这个比例后触发fullgc
8.‐XX:+UseCMSInitiatinpOccupancyOnly 老年代中对象达到这个比例后触发fullgc,每次
9.‐XX:+AlwaysPreTouch 强制操作系统把内存真正分配给IVM,而不是用时才分配。

7. 配置OOM时的内存dump文件和GC日志

增加了GC日志打印、OOM自动dump等配置内容

  • dump配置
-XX:+HeapDumpOnOutOfMemoryError 
-XX:+HeapDumpOnOutOfMemoryError   
-XX:HeapDumpPath=${LOGDIR}/  
  • GC日志配置
-Xloggc:/log/xxx/gc.log   
-XX:+PrintGCDateStamps   
-XX:+PrintGCDetails 

8. 通用JVM参数模板

  • CMS回收器参数模板
-Xms4g  
-Xmx4g  
-Xmn2g  
-Xss1m  
-XX:SurvivorRatio=8  
-XX:MaxTenuringThreshold=10  
-XX:+UseConcMarkSweepGC  
-XX:CMSInitiatingOccupancyFraction=70  
-XX:+UseCMSInitiatingOccupancyOnly  
-XX:+AlwaysPreTouch  
-XX:+HeapDumpOnOutOfMemoryError  
-verbose:gc  
-XX:+PrintGCDetails  
-XX:+PrintGCDateStamps  
-XX:+PrintGCTimeStamps  
-Xloggc:gc.log 
  • G1回收器参数模板
-Xms8g  
-Xmx8g  
-Xss1m  
-XX:+UseG1GC  
-XX:MaxGCPauseMillis=150  
-XX:InitiatingHeapOccupancyPercent=40  
-XX:+HeapDumpOnOutOfMemoryError  
-verbose:gc  
-XX:+PrintGCDetails  
-XX:+PrintGCDateStamps  
-XX:+PrintGCTimeStamps  
-Xloggc:gc.log

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jvm参数优化 的相关文章

  • 序列的排列?

    我有具体数量的数字 现在我想以某种方式显示这个序列的所有可能的排列 例如 如果数字数量为3 我想显示 0 0 0 0 0 1 0 0 2 0 1 0 0 1 1 0 1 2 0 2 0 0 2 1 0 2 2 1 0 0 1 0 1 1 0
  • 如何通过 javaconfig 使用 SchedulerFactoryBean.schedulerContextAsMap

    我使用 Spring 4 0 并将项目从 xml 移至 java config 除了访问 Service scheduleService 带注释的类来自QuartzJobBean executeInternal 我必须让它工作的 xml 位
  • 如何循环遍历所有组合,例如48 选择 5 [重复]

    这个问题在这里已经有答案了 可能的重复 如何在java中从大小为n的集合中迭代生成k个元素子集 https stackoverflow com questions 4504974 how to iteratively generate k
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • Java 集合的并集或交集

    建立并集或交集的最简单方法是什么Set在 Java 中 我见过这个简单问题的一些奇怪的解决方案 例如手动迭代这两个集合 最简单的单行解决方案是这样的 set1 addAll set2 Union set1 retainAll set2 In
  • java.lang.IllegalStateException:提交响应后无法调用 sendRedirect()

    这两天我一直在尝试找出问题所在 我在这里读到我应该在代码中添加一个返回 我做到了 但我仍然得到 java lang IllegalStateException Cannot call sendRedirect after the respo
  • jdbc mysql loginTimeout 不起作用

    有人可以解释一下为什么下面的程序在 3 秒后超时 因为我将其设置为在 3 秒后超时 12秒 我特意关闭了mysql服务器来测试mysql服务器无法访问的这种场景 import java sql Connection import java
  • 像 Java 这样的静态类型语言中动态方法解析背后的原因是什么

    我对 Java 中引用变量的动态 静态类型和动态方法解析的概念有点困惑 考虑 public class Types Override public boolean equals Object obj System out println i
  • volatile、final 和synchronized 安全发布的区别

    给定一个带有变量 x 的 A 类 变量 x 在类构造函数中设置 A x 77 我们想将 x 发布到其他线程 考虑以下 3 种变量 x 线程安全 发布的情况 1 x is final 2 x is volatile 3 x 设定为同步块 sy
  • tomcat 中受密码保护的应用程序

    我正在使用 JSP Servlet 开发一个Web应用程序 并且我使用了Tomcat 7 0 33 as a web container 所以我的要求是tomcat中的每个应用程序都会password像受保护的manager applica
  • Eclipse 选项卡宽度不变

    我浏览了一些与此相关的帖子 但它们似乎并不能帮助我解决我的问题 我有一个项目 其中 java 文件以 2 个空格的宽度缩进 我想将所有内容更改为 4 空格宽度 我尝试了 正确的缩进 选项 但当我将几行修改为 4 空格缩进时 它只是将所有内容
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • 如何使用 jUnit 将测试用例添加到套件中?

    我有 2 个测试类 都扩展了TestCase 每个类都包含一堆针对我的程序运行的单独测试 如何将这两个类 以及它们拥有的所有测试 作为同一套件的一部分执行 我正在使用 jUnit 4 8 在 jUnit4 中你有这样的东西 RunWith
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • Android:无法使用 DbHelper 和 Contract 类将数据插入 SQLite

    public class Main2Activity extends AppCompatActivity private EditText editText1 editText2 editText3 editText4 private Bu
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 长轮询会冻结浏览器并阻止其他 ajax 请求

    我正在尝试在我的中实现长轮询Spring MVC Web 应用程序 http static springsource org spring docs 2 0 x reference mvc html但在 4 5 个连续 AJAX 请求后它会
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其

随机推荐