JVM第七课:实战理解GC调优

GC常用参数

  • -Xmn -Xms -Xmx -Xss
    年轻代 最小堆 最大堆 栈空间大小
  • -XX:+UseTLAB
    使用TLAB,默认打开
  • -XX:+PrintTLAB
    打印TLAB的使用情况
  • -XX:TLABSize
    设置TLAB大小
  • -XX:+DisableExplictGC
    System.gc()不管用 ,FGC
  • -XX:+PrintGC
  • -XX:+PrintGCDetails
  • -XX:+PrintHeapAtGC
  • -XX:+PrintGCTimeStamps
  • -XX:+PrintGCApplicationConcurrentTime (低)
    打印应用程序时间
  • -XX:+PrintGCApplicationStoppedTime (低)
    打印暂停时长
  • -XX:+PrintReferenceGC (重要性低)
    记录回收了多少种不同引用类型的引用
  • -verbose:class
    类加载详细过程
  • -XX:+PrintVMOptions
  • -XX:+PrintFlagsFinal -XX:+PrintFlagsInitial
    必须会用
  • -Xloggc:opt/log/gc.log
  • -XX:MaxTenuringThreshold
    升代年龄,最大值15
  • 锁自旋次数 -XX:PreBlockSpin 热点代码检测参数-XX:CompileThreshold 逃逸分析 标量替换 …
    这些不建议设置

JVM调优第一步:了解JVM常用命令行参数

public class HelloGC {
    public static void main(String[] args) {
        System.out.println("hello gc~");
        List<byte[]> list = new LinkedList<>();
        for (; ; ) {
            list.add(new byte[1024 * 1024]);
        }
    }
}

区分概念:内存泄漏memory leak,内存溢出out of memory

内存泄漏就是有一块内存,我们用不到 但是GC也无法回收
内存溢出是分配内存时,发现内存不够用啦

这俩其实没啥必然的联系:
泄漏不一定导致溢出,内存总空间够大的话,浪费一点也不致命;
内存溢出不一定是由内存泄漏导致,内存总空间比较小,程序的对象又很多时,正常的使用也可能内存溢出

-XX:+PrintCommandLineFlags

输出JVM的默认参数:

-XX:InitialHeapSize=132253248
-XX:MaxHeapSize=2116051968
-XX:+PrintCommandLineFlags
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:-UseLargePagesIndividualAllocation -
XX:+UseParallelGC

-Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC

  • -Xmn 年轻代空间的最大值,-XX:MaxNewSize
  • -Xms 堆空间的最小值,-XX:InitialHeapSize,即初始大小
  • -Xmx 堆空间的最大值,-XX:MaxHeapSize
    一般把Xms和Xmx设置成一样的大小,避免堆的扩容和缩容所带来的资源消耗
  • -XX:+PrintGC 打印GC信息
    关于打印GC的参数还有:
    -XX:+PrintGCDetails 打印详细信息,这个下面详细看
    -XX:+PrintGCTimeStamps 时间戳
    -XX:+PrintGCCause 原因

执行后输出:
GC就是Young GC,年轻代的GC

-XX:InitialHeapSize=41943040 -XX:MaxHeapSize=62914560 -XX:MaxNewSize=10485760 -XX:NewSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
hello gc~
[GC (Allocation Failure) 8161K->6880K(39936K), 0.0027479 secs]
[GC (Allocation Failure) 14289K->14000K(39936K), 0.0024422 secs]
[GC (Allocation Failure) 21544K->21168K(39936K), 0.0031436 secs]
[GC (Allocation Failure) 28523K->28352K(39936K), 0.0025764 secs]
[Full GC (Ergonomics) 28352K->28242K(54784K), 0.0111999 secs]
[GC (Allocation Failure) 35611K->35538K(54784K), 0.0056506 secs]
[GC (Allocation Failure) 42869K->42706K(54784K), 0.0019941 secs]
[Full GC (Ergonomics) 42706K->42580K(60416K), 0.0571264 secs]
[GC (Allocation Failure) 49911K->49876K(60416K), 0.0116782 secs]
[Full GC (Ergonomics) 49876K->49749K(60416K), 0.0036178 secs]
[Full GC (Ergonomics) 57071K->56918K(60416K), 0.0036742 secs]
[Full GC (Ergonomics) 57946K->57942K(60416K), 0.0029635 secs]
[Full GC (Allocation Failure) 57942K->57924K(60416K), 0.0095233 secs]
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
at character07.HelloGC.main(HelloGC.java:11)

-XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags -XX:+PrintGC

-XX:+UseConcMarkSweepGC 使用CMS,观察CMS的GC
输出相比默认垃圾回收期PS+PO会更为详尽,
并且多了CMS Initial Mark

GC日志格式

在这里插入图片描述
关于上图中的Times含义:在linux中的times代表:
在这里插入图片描述

Heap Dump的含义(Linux)

eden space 5632K, 94% used [0x00000000ff980000,0x00000000ffeb3e28,0x00000000fff00000)
                            后面的内存地址指的是,起始地址,使用空间结束地址,整体空间结束地址

年轻代的total = eden + 1个survivor
在这里插入图片描述

调优前的基础概念

  1. 吞吐量throughput:用户代码执行时间 /(用户代码执行时间 + 垃圾回收时间)
    (可以理解为干正经事的时间占总时间的比例)
    吞吐量越大,JVM花在GC上的时间越少
  2. 响应时间:STW越短,响应时间越好
    这俩指标几乎是不可能兼得的,
    想要更高的吞吐量,就是要GC总体占用更少的CPU时间,这样的话,一旦需要STW,会STW很久(典型代表:CMS);
    想要更快的响应时间,就是要STW很短,需要有线程去不断的标记处理对象,但是这样的话,吞吐量势必会降低,因为GC占用更多的CPU时间了.

所谓调优,首先确定,追求啥?
吞吐量优先,还是响应时间优先?还是在满足一定的响应时间的情况下,要求达到多大的吞吐量

问题:
吞吐量优先:科学计算/数据挖掘,一般选择PS + PO
响应时间优先:网站 GUI API (1.8 选择G1)

什么是调优

  1. 根据需求进行JVM规划和预调优
  2. 优化运行JVM环境(慢,卡顿,一般是GC的STW过长了)
  3. 解决JVM运行过程中出现的各种问题(CPU 内存使用过高告警,OOM)

并发理解:

  • QPS
  • TPS
    淘宝双11并发历年最高54万,据说12306并发比淘宝更高,号称上百万

调优,从规划开始

  • 调优,从业务场景开始,没有业务场景的调优都是耍流氓
  • 无监控(压力测试,能看到结果),不调优
  • 步骤:
  1. 熟悉业务场景,选择优化的维度(没有最好的垃圾回收器,只有最合适的垃圾回收器)
    1. 响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)
    2. 吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
  2. 选择回收器组合
  3. 计算内存需求(经验值,不一定是越大越好, 有的从1.5G升到16G甚至还慢了很多)
  4. 选定CPU(越高越好)
  5. 设定年代大小、升级年龄
  6. 设定日志参数
    1. -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5
      -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
      使用5个GC日志文件,每个文件最大20M,超过5个时最新的文件会把最老的覆盖掉
    2. 或者每天产生一个日志文件
  7. 观察日志情况
  • 案例1:垂直电商,最高每日百万订单,处理订单系统需要什么样的服务器配置?

    这个问题比较业余,因为很多不同的服务器配置都能支撑(1.5G 16G 都有可能啊)
    我们做一个假设吧,1小时360000个订单。集中时间段, 100个订单/秒,(找一小时内的高峰期,可能是1000订单/秒)。我们就要找到这个最高峰的时间,保证你的架构能够承接的住。
    大多数情况下,是靠经验值,然后做压测。
    如果非要计算的话,你预估一下,一个订单对象产生需要多少内存?512K * 1000 = 500M内
    专业一点的问法:要求响应时间在多少时间的情况下,比如100ms,我们去挑一个市面上性价比比较高的服务器,做压测去测试,再不行加内存,再不行,就上云服务器…

  • 案例2:12306遭遇春节大规模抢票应该如何支撑?(架构问题)

    12306应该是中国并发量最大的秒杀网站:号称并发量最高100W
    架构模型:CDN -> LVS -> NGINX -> 业务系统 -> 100台机器,每台机器1W并发(单机10K问题),目前这个问题已解决,主要是用redis
    .
    业务流程:普通电商订单 -> 下单 ->订单系统(IO)减库存 ->生成订单,等待用户付款
    12306的一种可能的模型,是异步来进行的: 下单 -> 减库存 和 订单(redis kafka) 同时异步进行 ->等付款,付完款,持久化到Hbase, MySQL等等
    .
    减库存最后还会把压力压到一台服务器,怎么办?
    可以做分布式本地库存 + 单独服务器做库存均衡
    大流量的处理方法:分而治之,每台机器只减自己机器上有的库存
    流量倾斜的问题怎么解决?比如有的机器上已经没库存了,有的机器上还剩很多?
    这时候你还需要一台单独的服务器,去做所有服务器的平衡,如果某台服务器没库存了,从别的机器上挪一些过去。

  • 怎么得到一个事务会消耗多少内存?

    用压测来确定
    实际中一般是弄台机器,看能承受多少TPS?是不是达到目标?扩容或调优,让它达到目标即可

优化环境

  1. 有一个50万PV的资料类网站(从磁盘提取文档到内存)原服务器32位,1.5G的堆,用户反馈网站比较缓慢,因此公司决定升级,新的服务器为64位,16G的堆内存,结果用户反馈卡顿十分严重,反而比以前效率更低了

    1. 为什么原网站慢?
      很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢
    2. 为什么会更卡顿?
      内存越大,FGC时间越长
    3. 咋办?
      PS -> PN + CMS 或者 G1
  2. 系统CPU经常100%,如何调优?(面试高频)
    CPU100%那么一定有线程在占用系统资源,

    1. 找出哪个进程cpu高(top)
    2. 该进程中的哪个线程cpu高(top -Hp)
    3. 导出该线程的堆栈 (jstack)
    4. 查找哪个方法(栈帧)消耗时间 (jstack)
      工作线程占比高 | 垃圾回收线程占比高
  3. 系统内存飙高,如何查找问题?(面试高频

    1. 导出堆内存 (jmap)
    2. 分析 (jhat jvisualvm mat jprofiler … )
  4. 如何监控JVM

    1. jstat jvisualvm jprofiler arthas top…
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值