jvm命令

5. JVM常用命令及调优 - 图1

命令

jps

列出所有java进程信息

进程id
应用的jvm参数
启动的main方法

Jinfo

java进程信息

jstack

列表java进程内所有线程信息

作用:

  • 查死锁
  • 查使用率最高的cpu

jmap

堆内存导出 java memery analysis proceder

Java内存分析工具jmap

虚拟机工具-jmap

在jvm中类对象的数量 和 占用空间
jmap执行期间会对进程产生很大影响,甚至卡顿,吵适用高并发的电商项目
线上怎么操作:

  1. 设定heapDump oom时自动生成堆转储文件
  2. 高可用环境下,dump且重启集群中的某一台
  3. 在线定位
  4. tpccopy 线上请求导流到 测试小机房,然后用arthas做监控用jmap查看堆内存状态

jstat

jstat命令查看jvm的GC情况 (以Linux为例)

JVM调优命令-jstat

jstat -g 查看gc详细情况
阅读gc日志

JVM工具

? 使用什么工具做Jvm调试、排查?
(线上一般是不会给开端口号用于连接图形化调试工具)

  • 测试环境小机房 连接图形化界面
  • 线上出现问题,高可用环境下,停掉一台机器,临时申请一台服务器做Jvm调试
  • 【高端】在预发环境做 tcp copy ,库相同,代码相同,机器不同,完全模拟线上做调试

JVM工具

5. JVM常用命令及调优 - 图2

1. 图形化工具

不会在线上使用,一般用于:
上线前,测试小机房压测
可以在测试环境开远程端口,开发环境连接在图形化界面查看
也可以对集群环境的某台机器熔断,然后提供给远程端口,给开发环境连接图形化工具查看。

  • JProfiler
  • VisualVM
  • MAT
  • JConsole

2. arthas (阿里)

->点我去官方文档

dathboard

相当于top + jstat -g
根据cpu使用率倒排线程 ,显示各个jvm分代区域的内存使用情况

sysprop——查看和修改JVM的系统属性 kv键值列表

sysenv-环境参数

jvm

相当于jinfo
返回java se的详细信息
返回类加载情况 加载类总数 未加载数
返回垃圾回收器及期gc次数和花费时间
返回内存使用情况
返回线程总数、守护线程、死锁个数
返回操作系统信息
返回最大文件描述符个数,和打开fd个数

heapdump

相当于jmap ,会触发fullgc

thread

返回线程cpu使用率的倒排列表
thread 24(线程在列表的编号) 打印线程栈信息,相当于jstack

jad 反编辑类
  1. 查看线上服务器 jvm排查目标类的代码 是否是最新的
    redefine
    热更新 装载重新编译的class文件
    如果发现线上故障是因代码不是最新造成的比如sout(1), 期望是sout(2), 可以将编辑好的新class文件 redefine直接装载到系统。

Jmap堆导出文件分析工具

线上堆导出文件一般在10个G以上,以10g为例,mac pro 8+256 尝试1个小时没打开,i7+32g window 电脑用了十分钟左右打开。鉴于性能问题,jmap不到万一得已不会去,主要还是靠程序员的业务日志。

  • MAT

JVM调优

  1. 根据需求进行jvm规划和预调优

支持百万级并发需要机器多少 内存+CPU多少

  1. 优化运行jvm运行环境

慢、卡顿

  1. 解决jvm运行过程中出现的各种问题 (OOM)

参数类型

标准参数 - 可以被所有版本所有jvm识别
非标准参数 -X 只能被部分jvm识别 而不能被全部jvm识别
非稳定参数 -XX 随时可能被移除 常用的jvm调用参数还是xx开头的

-XX: +PrintFlagsFinal 约700个参数

GC常用参数

  • -Xmn -Xms -Xmx -Xss

在工业环境中,一般把Xms和Xmx设置为相同
年轻代 最小堆 最大堆 栈空间

  • -XX:+UseTLAB , +PrintTLAB, TLABSize

使用 TLAB,默认打开

  • -XX:+DisableExplictGC

使得System.gc()不管用

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

Paralle常用参数

-XX:SurvivorRatio 最生代比例
-XX:PreTenureSizeThreshold 大对象有多大
-XX:MaxTenuringThreshold
-XX:+ParallelGCThreads
并行收集器的线程数,同样适用于CMS,一般设为和cpu术数相同
-XX:+UseAdaptiveSizePolicy 自动选择各个分区大小比例

CMS常用参数

-XX:+UseConcMarkSweepGC
-XX+ParallelCMSThreads CMS线程数量
-XX:CMSInitiatingOccupancyFraction
使用多少比例的老年代后开始CMS收集,默认是68%,如果full gc频繁,应当调小。
-XX+CMSFullGCsBeforeCompaction 多少次FGC后进行压缩
-XX:CMSInitialtingPermOccupancyFraction 达到多少比例对Per回收
GCTimeRatio 设置GC时间占用程序运行时间的百分比
-XX:MaxGcPauseMillis 最大GC停顿时间,gc会尝试使用各种手段达到这个目标比如减小年轻代

G1的常用参数

-XX:UseG1GC
-XX:GCPauseMillis 建议值
-XX”GCPauseIntervalMillis GC间隔时间
-XX:+G1HeapRegionSize
分区大小,建议逐渐增大该值 1,2,4,8,16,32M
随着size增加,垃圾的存活时间更长,gc间隔更长,但每次gc的时间会更长,zgc对此做了优化。
G1NewSizePercent 最生代最小比例,默认为5%
G1MaxNewSizePercent 新生代最大比例 默认为60%
GCTimeRatio GC时间建议比例,G1会根据这个值调整堆空间
ConcGCThreads 线程数量
InitiatingHeapOccupancyPercent 启动G1的堆空间占用比例

面试题

  1. 项目发布流程
  • 测试多环境 用于各个业务线迭代开发新需求,业务需求之间相互隔离,开发没有Linux系统操作通道,只能查看日志,用于前后端对接和一轮测试
  • 测试小机房 用于二轮测试、此时代码已经相对稳定,很少会改bug后重启,测试同学会系统的测试需求的整体以及使用脚本或压测工具批量测试,同时开发同学也在此时关注新上线代码对系统性能的影响
  • 预发环境 这是一个完全模拟线上的环境,相同配置、相同数据库、redis/mq等打标隔离数据。用于上线前最后一次测试,测试验证和回归测试,也用于线上问题的跟踪排查。
  • 线上环境 除日志系统外,开发几乎无权限操作线上机器,但提供了丰富的大盘监控和堆栈导出

定位内存cpu负载高

线上卡顿,内存报警,cpu负载过,如何定位问题?
首先,通过jvm监控大盘、jdbc监控、cpu监控,收集三个大盘的数据信息。

cpu负载高

如果cpu负载过高,jstack导出线程栈,定位线程状态,重点关注WAITING BLOCKED
分析有无死锁、找到cpu占用率高的线程,做初步分析。根据打印的线程方法,找到对应的java类。查看相关源代码。

紧急热修

预发环境arthas jad命令反编译类信息,查看分析线程源代码。定位代码漏洞->重写代码->将重新编译好的class文件上传并使用arthas redefine加载到jvm,使代码快速生效,git提交最新代码->验证问题是否修复->测试回归,写发布单或通知运维重启(更快).

  1. safepoint 安全点是什么

让线程停在一个合适的位置,使得不会对一致性产生影响

  1. G1被回收的region之间有对象引用关系,g1怎么处理这个引用关系变更?

jvm的写屏障和volitile的内存屏障不是一个东西,jvm的写屏障是在jvm执行前后执行前置和后置操作,有点像spring的aop
拿g1来说,region1的对象A依赖region2的对象B,当region2回收时,对象A依赖的对象B被copy到另一个块region3, B的内存地址发生改变,g1需要将A对B依赖的引用地址变更。这里用到了jvm写屏障(postWriteBarrier),当Bcopy到region3指令执行之后,调用该屏障,对所有对B有依赖的对象的对象引用地址做修改。

  1. 为什么压缩指针32G会失效?

-XX:+UseCompressClassPointer 使用类指针压缩,使得对象内存布局中的classpointer以4字节存储(原来是8)
-XX:+UseCompressedOops (Ordinary Object Pointers)压缩普通对象引用指针,一个对象引用一个对象,保存的是内存地址,不开压缩占用8个字段,开压缩占用4个字节。这个内存压缩,在内存条容量超过32G时会失效.