栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 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

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

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

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

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

并发理解:

QPSTPS
淘宝双11并发历年最高54万,据说12306并发比淘宝更高,号称上百万 调优,从规划开始

调优,从业务场景开始,没有业务场景的调优都是耍流氓无监控(压力测试,能看到结果),不调优步骤:

    熟悉业务场景,选择优化的维度(没有最好的垃圾回收器,只有最合适的垃圾回收器)
      响应时间、停顿时间 [CMS G1 ZGC] (需要给用户作响应)吞吐量 = 用户时间 /( 用户时间 + GC时间) [PS]
    选择回收器组合计算内存需求(经验值,不一定是越大越好, 有的从1.5G升到16G甚至还慢了很多)选定CPU(越高越好)设定年代大小、升级年龄设定日志参数
      -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个时最新的文件会把最老的覆盖掉或者每天产生一个日志文件
    观察日志情况

案例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?是不是达到目标?扩容或调优,让它达到目标即可

优化环境

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

      为什么原网站慢?
      很多用户浏览数据,很多数据load到内存,内存不足,频繁GC,STW长,响应时间变慢为什么会更卡顿?
      内存越大,FGC时间越长咋办?
      PS -> PN + CMS 或者 G1

    系统CPU经常100%,如何调优?(面试高频)
    CPU100%那么一定有线程在占用系统资源,

      找出哪个进程cpu高(top)该进程中的哪个线程cpu高(top -Hp)导出该线程的堆栈 (jstack)查找哪个方法(栈帧)消耗时间 (jstack)
      工作线程占比高 | 垃圾回收线程占比高

    系统内存飙高,如何查找问题?(面试高频

      导出堆内存 (jmap)分析 (jhat jvisualvm mat jprofiler … )

    如何监控JVM

      jstat jvisualvm jprofiler arthas top…
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/709058.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号