一.文章介绍
首先带我们先来了解下JVM的内存结构:
- Metaspance = Class、Package、Method、Field、字节码、常量池、符号引用等等。
- CCS = 32位指针的Class(压缩类空间)
- CodeCache = JIT编译后的本地代码、JNI使用的C代码
二JNI.基于JDK命令行工具的监控
1.JVM的参数类型
1.标准参数:功能和输出的参数都是很稳定的 在未来的JVM版本中不会改变 可以使用java -help检索出所有的标准参数
2.X参数:非标准化参数 在未来的版本可能会改变 所有的参数都用-X开始 可以使用java -X检索
-Xint:解释执行
-Xcomp :第一次使用就编译成本地代码
-Xmixed :混合模式,JVM自己来决定是否编译成本地代码
3.XX参数:非标准 很长一段时间不会列出来 用于JVM开发的debug和调优
boolean : -XX:+UseConcMarkSweepGC :启用CMS垃圾收集器
-XX:+UseG1GC :启用G1 垃圾收集器
非boolean类型 : -XX:MaxGCPauseMillis=500 //young区GC的回收的时间
-XX:GCTimeRatio=19 //吞吐量 也就是垃圾回收时间和非垃圾回收时间的比例
注意:-Xms 等价于 -XX:InitialHeapSize //jvm初始堆内存 1/64
-Xmx 等价于 -XX:MaxHeapSize //jvm最大堆内存 1/4
-xss 等价于 -XX:TreadStackSize //堆栈的大小
2.查看JVM运行时参数
-XX:+PrintFlagsInitial //查看初始值
-XX:+PrintFlagsFinal //查看最终值
-XX:+UnlockExperimentslVMOptions //解锁实验参数
jps:撞门查看java进程
jinfo:查看正在运行jvm参数
例如:jinfo -flag MaxHeapSize pid
jinfo -flag UseG1GC pid
jinfo -flag UseConcMarkSweepGC pid
jinfo -flag UseParallelGC
3.jstat查看JVM统计信息
option:-class,-compiler,-gc,-printcompilation
-class: jstat -class 23029 1000 10
-gc: jstat -gc 23029
-gc输出的结果:
S0C、S1C、SOU、S1U:S0和S1的总量与使用量
EC、EU:Eden区总量与使用量
OC、OU:Old区总量与使用量
MC、MU:Metaspace区总量与使用量
CCSC、CCSU:压缩类空间总量与使用量
YGC、YGCT:YoungGC的次数与时间
FGC、FGCT:FullGC的次数与时间
GCT:总的GC时间
-compiler、-printcompilation:jstat -compiler 23029
4.演示内存溢出
5.如何导出内存映像文件
1.内存溢出自动导出(不建议使用)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
2.使用jmap命令手动导出
jmap -dump:format=b,file=heap.hprof XXX
6.MAT分析内存溢出
7.jstack与线程的状态
jstack XXXX
top XXX -p -H
线程状态图:
java线程状态:
NEW 、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED
https://mp.weixin.qq.com/s/GsxeFM7QWuR--Kbpb7At2w
8.jstack实战死循环与死锁
三.基于JVisualVM的可视化监控
1.监控本地java进程
https://visualvm.github.io/pluginscenters.html
https://visualvm.github.io/documentation.html
2.监控远程的java进程
JAVA_OPTS="$JAVA_OPTS
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9004
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.net.preferIPv4Stack=true
-Djava.rmi.server.hostname=10.110.3.62"
四.基于Btrace的监控调试
五.Tomcat性能监控与调优
六.JVM层GC调优
JVM层GC调优
程序计数器PC Register:JVM支持多线程同时执行,每一个线程都有自己的PC Register,线程正在执行的方法叫做当前方法,如果是java代码,
PC Register里面存放的就是当前正在执行的指令的地址,如果是C代码,则为空。
虚拟机栈JVM Stacks: Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同。
虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,用于储存局部变量表、操作数栈、动态链接
方法出口等详细,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。(线程堆栈)
堆Heap:Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域
的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。
方法区Method Area:方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的是与Java堆区分开来。
常量池Run-Time Constant Pool:运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,
用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
本地方法栈Native Method Stacks:本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,
而本地方法栈则为虚拟机使用的Native方法服务。
常用参数:
-Xms -Xmx
-XX:NewSize -XX:MaxNewSize
-XX:NewRation -XX:SurvivorRatio
-XX:MetaspaceSize -XX:MaxMetaspaceSize
-XX:+UseCompressedClassPointers
-XX:CompressedClassSpaceSize
-XX:InitialCodeCacheSize
-XX:ReservedCodeCacheSize
垃圾回收算法:
引用计数
思想:枚举根节点,做可达性分析。
根节点:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量应用、本地方法栈的变量等等。
标记清除:
算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有。
缺点:1、效率不高:标记和清除两个过程的效率都不高。
2、产生碎片:碎片太多会导致提前GC。
复制:
它将可用内存按照容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把
已经使用过的内存空间一次性清理掉。
优缺点:实现简单,运行高效,但是空间利用率低。
标记整理:
标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
优缺点:没有了内存碎片,但是整理内存比较耗时。
JVM的垃圾回收算法:分带垃圾回收
Young区用复制算法
Old区用标记清除或者标记整理
对象分配:
对象优先在Eden区分配
大对象直接进入老年代:-XX:PretenureSizeThreshold
垃圾收集器:
串行收集器Serial:Serial、Serial Old
并行收集器Parallel:Parallel Scavenge、Parallel Old,(吞吐量优先的收集器)
并发收集器Concurrent:CMS、G1,(停顿时间优先的收集器)
并行VS并发:
并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。适合科学计算、后台处理等弱交互场景。
并发:指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),垃圾收集线程在执行的时候
不会停顿用户程序的执行。适合对响应时间有需求的场景,比如Web。
停顿时间VS吞吐量
停顿时间:垃圾收集器做垃圾回收中断应用执行的时间。 -XX:MaxGCPauseMillis
吞吐量:花在垃圾收集的时间和花在应用时间的占比。 -XX:GCTimeRatio=?,垃圾收集时间占:1/1+?
串行收集器:
-XX:+UseSerialGC -XX:+UseSerialOldGC
并行收集器:
吞吐量优先
-XX:UseParallelGC -XX:+UseParallelOldGC
Server模式下的默认收集器
并发收集器:
响应时间优先
CMS:-XX:+UseConcMarkSweepGC -XX:+UseParNewGC
G1: -XX:+UseG1GC
垃圾收集器搭配
配图
如何选择立即收集器
1.优先调整堆的大小让服务器自己来选择。
2.如果内存小于100M,使用串行收集器。
3.如果是单核,并且没有停顿时间的要求,串行或者JVM自己选。
4.如果允许停顿时间超过1秒,选择并行或者JVM自己选。
5.如果响应时间最重要,并且不能超过1秒,使用并发收集器。
收集器详解:
Parallel Collector
-XX:+UseParallelGC手动开启,Server默认开启
-XX:ParallelGCThreads=<N> 多少个GC线程 CPU>8 N=5/8 CPU<8 N=CPU
Parallel Collector Ergonomics
-XX:MaxGCPauseMillis=<N>
-XX:GCTimeRatio=<N>
-Xms<N>
动态内存调整
-XX:YoungGenertionSizeIncrement=<Y>
-XX:TenuredGenerationSizeIncrement=<T>
-XX:AdaptiveSizeDecrementScaleFactor=<D>
CMS Collector
特点:1.并发收集器
2.低停顿 低延迟
3.老年代收集器
CMS垃圾收集过程
1.CMS initial mark:初始标记Root,STW
2.CMS concurent mark:并发标记
3.CMS-concurent-preclean:并发预清理
4.CMS remark:重新标记,STW
5.CMS concurent sweep:并发清除
6.CMS-concurent-reset:并发重置
CMS缺点
1.CPU敏感
2.浮动垃圾
3.空间碎片
CMS的相关参数
-XX:ConcGCThreads: 并发的GC线程数
-XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩
-XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次
-XX:CMSInitiatingOccupancyFraction:触发FullGC
-XX:+UseCMSInitiatingOccupancyOnly:是否动态可调的
-XX:+CMScavengeBeforeRemark:FullGC之前先做YGC
-XX:+CMSClassUnloadingEnabled:启动回收Perm区
iCMS
1.适用于单核或者双核
G1 Collector
简介:
The first focus of G1 is to provide a solution for users running applications that require large heaps with limited GC latency. This means heap sizes of around 6 GB or larger, and a stable and predictable pause time below 0.5 seconds.
G1的第一个重点是为运行需要具有有限GC延迟的大堆的应用程序的用户提供解决方案。这意味着堆大小约为6 GB或更大,并且稳定且可预测的暂停时间低于0.5秒
1.Region
图
2.SATB:Snapshot-At-The-Beginning,它是通过Root Tracing得到的,GC开始时候存活对象的快照。
3.RSet:记录了其他Region中的对象引用本Region中对象的关系,属于point-into结构(谁引用了我的对象)
YoungGC
1.新对象进入Eden区
2.存活对象拷贝到Survivor区
3.存活时间达到年龄阀值时,对象晋升到Old区
MixedGC
1.不是FullGC,回收所有的Young和部分Old
2.global concurrent marking
:1) Initial marking phase:标记GC Root,STW
:2) Root region scanning phase:标记存活Region
:3) Concurrent marking phase:标记存活的对象
:4) Remark phase:重新标记,STW
:5) Cleanup phase:部分STW
时机:
InitiatingHeapOccupancyPercent:堆占有率达到这个数值则触发global concurrent marking,默认45%
G1HeapWastePercent:在global concurent marking结束之后,可以知道区有多少空间要被回收,在每次YGC之后和再次
发生Mixed GC之前,会检查垃圾占比是否达到此参数,只有达到了,下次才会发生Mixed GC。
MixedGC相关参数
1.G1MixedGCLiveThresholdPercent:Old区的region被回收时候的存活对象占比
2.G1MixedGCCountTarget:一次global concurent marking之后,最多执行Mixed GC的次数
3.G1OldCSetRegionThresholdPercent:一次Mixed GC中能被选入CSet的最多old区的region数量
4.-XX:+UseG1GC 开启G1
5.-XX:G1HeapRegionSize=n,region的大小,1-32M,2048个
6.-XX:MaxGCPauseMillis=200 最大停顿时间
7.-XX:G1NewSizePercent、-XX:G1MaxNewSizePercent
8.-XX:G1ReservePercent=10 保留防止to spance溢出
9.-XX:ParallelGCThreads=n
10.-XX:ConcGCThreads=n 并发线程数=1/4*并行
最佳实践:
1.年轻代大小:避免使用-Xmn、-XX:NewRatio等显式设置Young区大小,会覆盖暂停时间目标。
2.暂停时间目标:暂停实践不要太严苛,其吞吐量目标是90%的应用程序时间和10%的垃圾回收时间,不免直接影响到吞吐量。
是否需要切换到G1:
1.50%以上的堆被存活对象占用
2.对象分配和晋升的速度变化非常大
3.垃圾回收的时间特别长,超过了1秒
七.JVM字节码与Java代码层调优