JVM学习六

JVM学习六

      • GC调优
        • JVM常用命令行参数
        • 常见垃圾回收器组合参数设定
        • GC日志详解
      • JVM调优
        • 调优前的概念
        • 什么是调优
        • 调优规划和预调优
        • 优化环境

GC调优

JVM常用命令行参数

参数查询(linux环境):
在这里插入图片描述

  • JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html

  • HotSpot参数分类

    标准: - 开头,所有的HotSpot都支持

    非标准:-X 开头,特定版本HotSpot支持特定命令

    不稳定:-XX 开头,下个版本可能取消

    java -version

    java -X

小程序:

public class T01_HelloGC {
    public static void main(String[] args) {
        System.out.println("Hello GC");
        List list = new LinkedList();
        for(;;) {
            byte[] b = new byte[1024 * 1024];
            list.add(b);
        }
    }
}

首先来看:java -XX:+PrintCommandLineFlags HelloGC
JVM学习六_第1张图片

输出如下信息:

-XX:InitialHeapSize=257560512 -XX:MaxHeapSize=4120968192 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
Connected to the target VM, address: '127.0.0.1:11937', transport: 'socket'
Hello GC
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


Process finished with exit code 1

initialHeapSize起始堆大小,
maxHeapSize最大堆大小
注意:
内存有两种方式对虚拟机产生影响,第一种是内存泄漏(memory leak,废了的对象未回收空间)【不一定会产生内存溢出】,第二种是内存溢出(out of memory)

2、指令2:-Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC
一般我们-Xms和-Xmx堆最小和最大的大小设置成一样的,因为这样可以避免堆空间的弹性伸缩【当空间不够用了往大了弹,当空间大于我们使用的时候则往小弹】
-xmn:设置年轻代的大小
此外除了PrintGC以外还有PrintGCDetails,PrintGCTimeStamps【打印GC时间信息】,PrintGCCauses【打印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 
Connected to the target VM, address: '127.0.0.1:12207', transport: 'socket'
Hello GC
GC:产生的YGC  GC产生的原因:(Allocation Failure) 年轻代堆经过一次回收之后从多大变成多大:7782K->6176K(39936K)
[GC (Allocation Failure)  7782K->6176K(39936K), 0.0019873 secs]
[GC (Allocation Failure)  13666K->13360K(39936K), 0.0024044 secs]
[GC (Allocation Failure)  20761K->20432K(39936K), 0.0012763 secs]
[GC (Allocation Failure)  27754K->27664K(39936K), 0.0012923 secs]
//Old区域越来越大产生FullGC
[Full GC (Ergonomics)  27664K->27309K(54272K), 0.0076299 secs]
[GC (Allocation Failure)  34633K->34701K(53760K), 0.0021145 secs]
[GC (Allocation Failure)  42019K->41901K(50688K), 0.0013010 secs]
[Full GC (Ergonomics)  41901K->41646K(56832K), 0.0025557 secs]
[GC (Allocation Failure)  44794K->44846K(58368K), 0.0007178 secs]
[Full GC (Ergonomics)  44846K->44718K(58368K), 0.0020880 secs]
[GC (Allocation Failure)  47858K->47886K(58368K), 0.0007106 secs]
[Full GC (Ergonomics)  47886K->47790K(58368K), 0.0027907 secs]
[GC (Allocation Failure)  50925K->50958K(58368K), 0.0008849 secs]
[Full GC (Ergonomics)  50958K->50862K(58368K), 0.0028238 secs]
[Full GC (Ergonomics)  53994K->53934K(58368K), 0.0036053 secs]
[Full GC (Allocation Failure)  53934K->53918K(58368K), 0.0084963 secs]
//FullGC也清理不掉了则抛出OOM异常
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Process finished with exit code 1

再来看下面这个:-XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags -XX:+PrintGC
会发现使用CMS垃圾回收器,回收对象会更频繁。

-XX:InitialHeapSize=257560512 -XX:MaxHeapSize=4120968192 -XX:MaxNewSize=1134141440 -XX:MaxTenuringThreshold=6 -XX:OldPLABSize=16 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:-UseLargePagesIndividualAllocation -XX:+UseParNewGC 
Connected to the target VM, address: '127.0.0.1:8895', transport: 'socket'
Hello GC
[GC (Allocation Failure)  66830K->62272K(243520K), 0.0180578 secs]
[GC (Allocation Failure)  129432K->127830K(243520K), 0.0212170 secs]
//初始标记
[GC (CMS Initial Mark)  128854K(243520K), 0.0001601 secs]
[GC (Allocation Failure)  194666K->194294K(263052K), 0.0213963 secs]
[GC (Allocation Failure)  261144K->260829K(329872K), 0.0209205 secs]
[GC (Allocation Failure)  327688K->327391K(395664K), 0.0267197 secs]
[GC (Allocation Failure)  394255K->393955K(462484K), 0.0658935 secs]
[GC (Allocation Failure)  460825K->460518K(529304K), 0.0351816 secs]
[GC (Allocation Failure)  527389K->527080K(596124K), 0.0232964 secs]
[GC (Allocation Failure)  593953K->593641K(661916K), 0.0210760 secs]
[GC (Allocation Failure)  660514K->660205K(728736K), 0.0188286 secs]
[GC (Allocation Failure)  727079K->726768K(795556K), 0.0205322 secs]
[GC (Allocation Failure)  793642K->793332K(862376K), 0.0234916 secs]
[GC (Allocation Failure)  860207K->859893K(928168K), 0.0210479 secs]
[GC (Allocation Failure)  926767K->926455K(994988K), 0.0200434 secs]
[GC (Allocation Failure)  993330K->993018K(1061808K), 0.0192223 secs]
[GC (Allocation Failure)  1059893K->1059582K(1128628K), 0.0200241 secs]
[GC (Allocation Failure)  1126457K->1126145K(1194420K), 0.0188897 secs]
[GC (Allocation Failure)  1193020K->1192706K(1261240K), 0.0190581 secs]
[GC (Allocation Failure)  1259580K->1259266K(1328060K), 0.0214457 secs]
[GC (Allocation Failure)  1326141K->1325831K(1394880K), 0.0243835 secs]
[GC (Allocation Failure)  1392705K->1392397K(1460672K), 0.0234791 secs]
[GC (Allocation Failure)  1459272K->1458958K(1527492K), 0.0245448 secs]
[GC (Allocation Failure)  1525832K->1525518K(1594312K), 0.0220823 secs]
[GC (Allocation Failure)  1592393K->1592081K(1661132K), 0.0207116 secs]
[GC (Allocation Failure)  1658956K->1658643K(1726924K), 0.0199758 secs]
[GC (Allocation Failure)  1725518K->1725208K(1793744K), 0.0197700 secs]
[GC (Allocation Failure)  1792083K->1791766K(1860564K), 0.0199459 secs]
[GC (Allocation Failure)  1858641K->1858329K(1927384K), 0.0192443 secs]
[GC (Allocation Failure)  1925204K->1924893K(1993176K), 0.0210410 secs]
[GC (Allocation Failure)  1991768K->1991456K(2059996K), 0.0196798 secs]
[GC (Allocation Failure)  2058331K->2058017K(2126816K), 0.0206533 secs]
[GC (Allocation Failure)  2124891K->2124581K(2193636K), 0.0213093 secs]
[GC (Allocation Failure)  2191456K->2191146K(2259428K), 0.0198410 secs]
[GC (Allocation Failure)  2258020K->2257706K(2326248K), 0.0195975 secs]
[GC (Allocation Failure)  2324581K->2324269K(2393068K), 0.0184608 secs]
[GC (Allocation Failure)  2391143K->2390831K(2459888K), 0.0220385 secs]
[GC (Allocation Failure)  2457706K->2457396K(2525680K), 0.0213528 secs]
[GC (Allocation Failure)  2524271K->2523956K(2592500K), 0.0220963 secs]
[GC (Allocation Failure)  2590831K->2590519K(2659320K), 0.0231794 secs]
[GC (Allocation Failure)  2657394K->2657081K(2726140K), 0.0248919 secs]
[GC (Allocation Failure)  2723956K->2723642K(2791932K), 0.0229990 secs]
[GC (Allocation Failure)  2790517K->2790209K(2858752K), 0.0217714 secs]
[GC (Allocation Failure)  2857083K->2856769K(2925572K), 0.0201481 secs]
[GC (Allocation Failure)  2923644K->2923332K(2992392K), 0.0206791 secs]
[GC (CMS Final Remark)  2924356K(2992392K), 0.0017975 secs]
[Full GC (Allocation Failure)  2989853K->2988836K(2994432K), 0.3383998 secs]
[Full GC (Allocation Failure)  2993570K->2992932K(2994432K), 0.0073082 secs]
[Full GC (Allocation Failure)  2992932K->2992916K(2994432K), 0.5134662 secs]
[GC (CMS Initial Mark)  2992916K(2994432K), 0.0001844 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Process finished with exit code 1

  1. java -XX:+PrintFlagsInitial 默认参数值【可以查看所有JVM启动的参数】
    JVM学习六_第2张图片

java -XX:+PrintFlagsFinal 最终参数值
JVM学习六_第3张图片

java -XX:+PrintFlagsFinal | grep xxx 找到对应的参数
java -XX:+PrintFlagsFinal -version |grep GC
注意windows中用findstr:
JVM学习六_第4张图片

常见垃圾回收器组合参数设定

  • -XX:+UseSerialGC = Serial New (DefNew) + Serial Old

    • 小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和JDK版本自动选择收集器
  • -XX:+UseParNewGC = ParNew + SerialOld

    • 这个组合已经很少用(在某些版本中已经废弃)
    • https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future
  • -XX:+UseConcurrentMarkSweepGC = ParNew + CMS + Serial Old

  • -XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】

  • -XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old

  • -XX:+UseG1GC = G1

  • Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC

    • java +XX:+PrintCommandLineFlags -version
    • 通过GC的日志来分辨
  • Linux下1.8版本默认的垃圾回收器到底是什么?

    • 1.8.0_181 默认(看不出来)Copy MarkCompact
    • 1.8.0_222 默认 PS + PO

GC日志详解

还是上面的那个程序:
设置JVM参数: -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGCDetails【设置输出GC的详细信息】

-XX:InitialHeapSize=41943040 -XX:MaxHeapSize=62914560 -XX:MaxNewSize=10485760 -XX:NewSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
Connected to the target VM, address: '127.0.0.1:10121', transport: 'socket'
Hello GC
[GC (Allocation Failure) [PSYoungGen: 7782K->1016K(9216K)] 7782K->6176K(39936K), 0.0016007 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 【用户态占用时间,内核态占用时间,总占用多少时间】
[GC (Allocation Failure) [PSYoungGen: 8506K->1000K(9216K)] 13666K->13344K(39936K), 0.0015698 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8401K->920K(9216K)] 20745K->20440K(39936K), 0.0022407 secs] [Times: user=0.13 sys=0.03, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 8242K->1016K(9216K)] 27762K->27704K(39936K), 0.0015286 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 1016K->0K(9216K)] [ParOldGen: 26688K->27309K(45056K)] 27704K->27309K(54272K), [Metaspace: 3326K->3326K(1056768K)], 0.0090290 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[GC (Allocation Failure) [PSYoungGen: 7324K->224K(8704K)] 34633K->34701K(53760K), 0.0016893 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 7541K->1248K(5632K)] 42019K->41869K(50688K), 0.0011368 secs] [Times: user=0.08 sys=0.06, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 1248K->0K(5632K)] [ParOldGen: 40621K->41646K(51200K)] 41869K->41646K(56832K), [Metaspace: 3326K->3326K(1056768K)], 0.0022957 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 3148K->2144K(7168K)] 44794K->44814K(58368K), 0.0008460 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2144K->0K(7168K)] [ParOldGen: 42670K->44718K(51200K)] 44814K->44718K(58368K), [Metaspace: 3326K->3326K(1056768K)], 0.0026632 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 3140K->2176K(7168K)] 47858K->47918K(58368K), 0.0010636 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2176K->0K(7168K)] [ParOldGen: 45742K->47790K(51200K)] 47918K->47790K(58368K), [Metaspace: 3326K->3326K(1056768K)], 0.0019098 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 3135K->2144K(7168K)] 50925K->50958K(58368K), 0.0007480 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 2144K->0K(7168K)] [ParOldGen: 48814K->50862K(51200K)] 50958K->50862K(58368K), [Metaspace: 3326K->3326K(1056768K)], 0.0020609 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 3131K->3072K(7168K)] [ParOldGen: 50862K->50862K(51200K)] 53994K->53934K(58368K), [Metaspace: 3326K->3326K(1056768K)], 0.0017782 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 3072K->3072K(7168K)] [ParOldGen: 50862K->50846K(51200K)] 53934K->53918K(58368K), [Metaspace: 3326K->3326K(1056768K)], 0.0071556 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
Heap
 PSYoungGen      total 7168K, used 3212K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 4096K, 78% used [0x00000000ff600000,0x00000000ff923038,0x00000000ffa00000)
  from space 3072K, 0% used [0x00000000ffa00000,0x00000000ffa00000,0x00000000ffd00000)
  to   space 3072K, 0% used [0x00000000ffd00000,0x00000000ffd00000,0x0000000100000000)
 ParOldGen       total 51200K, used 50846K [0x00000000fc400000, 0x00000000ff600000, 0x00000000ff600000)
  object space 51200K, 99% used [0x00000000fc400000,0x00000000ff5a7b30,0x00000000ff600000)
 Metaspace       used 3357K, capacity 4620K, committed 4864K, reserved 1056768K
  class space    used 360K, capacity 392K, committed 512K, reserved 1048576K

其后的堆信息:
年轻代,total=eden+1个survivor,因为复制算法,所以每次只会使用一个S0或者S1区域,还有一块区域空着留着复制
turnured generation是old区,说明了总的空间是多少
[0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)
如上地址信息分别代表起始地址是在哪,然后使用空间的结束地址,以及整体空间的结束地址。

metaspace元数据区
class space 专门给class信息做存储的空间

JVM调优

调优前的概念

1、吞吐量:用户代码时间/(用户代码执行时间+垃圾回收时间) ->吞吐量大说明程序越好【大量的计算用在程序计算上面,垃圾回收计算相对较少】
2、响应时间:STW越短,响应时间越好【将大量时间用在垃圾回收上面】响应时间目前是要求最多的
需要确定:
吞吐量优先还是响应时间优先?还是在满足一定的响应时间的情况下,要求多大的吞吐量。

如做科学计算及数据挖掘:吞吐量优先(一般采用PS+PO)
响应时间优先:网站,GUI界面,对外提供的API(1.8 G1或者PN+CMS)【G1(推荐内存够大的情况使用)CMS的吞吐量要比CMS低一些,大概在15%左右】

什么是调优

1、根据需求进行JVM规划和预调优
2、优化运行JVM运行环境
3、解决JVM运行过程中出现的各种问题(OOM【只是一部分】)

调优规划和预调优

调优:从业务场景开始,没有业务场景的调优就是耍流氓
无监控【这里的监控指的是压力测试】,不调优
步骤:
1、熟悉业务场景(没有最好的垃圾回收器,只有最合适的垃圾回收期)
2、响应时间,停顿时间【CMS G1 ZGC】(需要给用户做响应)
3、吞吐量:用户代码时间/(用户代码执行时间+垃圾回收时间)【PS垃圾回收器】
【根据以上需求选定回收器的组合】
4、计算内存需求(内存大回收的慢一些,内存小回收的快一些)
5、选定CPU(越高越好)
6、设定日志参数:
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause

-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log :日志文件,产生按照系统时间产生
-XX:+UseGCLogFileRotation: 循环产生五个日志文件
-XX:NumberOfGCLogFiles=5 :五个记录GC日志的文件
-XX:GCLogFileSize=20M:每个文件的大小为20M
能控制日志文件的总大小为100M

案例1:垂直电商【只卖某种产品】,最高每日百万订单,处理订单系统需要什么样的服务器配置?

很多服务器的配置都能支撑,可以找交易量最高峰的时间,假设每天五点到七点有720000订单在这两个
小时产生,平均一小时产生360000订单,每秒产生100个订单(找一小时内的高峰期,1000订单/秒)
在这个高峰时间架构要能撑住。【经验值:
一个订单产生需要多少内存?按照512k来计算, 1000个订单高峰则需要500M内存
如果要求响应时间在100ms的情况下,做压测来估算。
所以一般需要估算系统的内存以及CPU,不行则加CPU扩展内存,实在不行则上云

案例2:12306遭遇春节大规模抢票应该如何支撑?
号称并发量100W最高
CDN【在全国各个地方做缓存】->LVS->NGINX->业务系统->每台机器1W并发(单机10k问题),100台机器
12306用户下单可能会用到的模型为:用户下单->减库存和订单(redis kafka)同时异步进行->等待付款减库存
最后还会把压力压倒一台服务器。【可以做分布式本地库存+单独服务器做库存均衡】
大流量处理方式:分而治之

优化环境

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

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

如果一个系统CPU经常100%,如何调优?
CPU100%那么一定有线程在占用系统资源
1、找出哪个进程CPU高(top)
2、该进程中的哪个线程CPU高(top -HP)
3、导出该线程的堆栈(jstack)
4、查找哪个方法(栈帧)消耗时间(jstack)
5、区分是工作线程占比高还是垃圾回收线程占比高
系统内存飙高,如何查找问题?
1、导出堆内存(jmap)
2、分析(jhat,jvisualvm mat jprofiler)

你可能感兴趣的:(JVM,jvm,学习,java)