精华内容
下载资源
问答
  • jvm实战调优

    2021-02-17 17:21:21
    文章目录实战调优常用参数GC常用参数Parallel常用参数CMS常用参数G1常用参数常用调优工具JDK内置的命令行可视化界面部分情况分析项目调优 实战调优 慢慢补充,先这样吧 常用参数 GC常用参数 -Xmn:年轻代 -Xms:...

    实战调优

    慢慢补充,先这样吧

    常用参数

    GC常用参数

    • -Xmn:年轻代
    • -Xms:最小堆
    • -Xmx :最大堆
    • -Xss:栈空间
    • -XX:+UseTLAB:使用TLAB,默认打开
    • -XX:+PrintTLAB:打印TLAB的使用情况
    • -XX:TLABSize:设置TLAB大小
    • -XX:+DisableExplictGC:禁用System.gc()不管用 ,防止FGC
    • -XX:+PrintGC:打印GC日志
    • -XX:+PrintGCDetails:打印GC详细日志信息
    • -XX:+PrintHeapAtGC:打印GC前后的详细堆栈信息
    • -XX:+PrintGCTimeStamps:打印时间戳
    • -XX:+PrintGCApplicationConcurrentTime:打印应用程序时间
    • -XX:+PrintGCApplicationStoppedTime:打印暂停时长
    • -XX:+PrintReferenceGC:记录回收了多少种不同引用类型的引用
    • -verbose:class:类加载详细过程
    • -XX:+PrintVMOptions:jvm参数
    • -XX:+PrintFlagsFinal:该命令可以查看所有JVM参数启动的初始值,必须会用
    • -Xloggc:opt/log/gc.log:gc日志的路径以及文件名称
    • -XX:MaxTenuringThreshold:升代年龄,最大值15

    Parallel常用参数

    • -XX:SurvivorRatio:年轻代中eden和from/to的比值。比如设置3就是eden:survivor=3:2,也就是from和to各占1,eden占用3
    • -XX:PreTenureSizeThreshold:大对象到底多大-XX:MaxTenuringThreshold:升代年龄,最大值15
    • -XX:+ParallelGCThreads:并行收集器的线程数,同样适用于CMS,一般设为和CPU核数相同
    • -XX:+UseAdaptiveSizePolicy:自动选择各区大小比例

    CMS常用参数

    • -XX:+UseConcMarkSweepGC:设置年老代为并发收集
    • -XX:ParallelCMSThreads:CMS线程数量
    • -XX:CMSInitiatingOccupancyFraction:使用多少比例的老年代后开始CMS收集,默认是68%(近似值),如果频繁发生SerialOld卡顿,应该调小,(频繁CMS回收)
    • -XX:+UseCMSCompactAtFullCollection:在FGC时进行压缩
    • -XX:CMSFullGCsBeforeCompaction:多少次FGC之后进行压缩
    • -XX:+CMSClassUnloadingEnabled:年老代启用CMS,但默认是不会回收永久代(Perm)的。此处对Perm区启用类回收,防止Perm区内存满。
    • -XX:CMSInitiatingPermOccupancyFraction:达到什么比例时进行Perm回收
    • GCTimeRatio:设置GC时间占用程序运行时间的百分比
    • -XX:MaxGCPauseMillis:停顿时间,是一个建议时间,GC会尝试用各种手段达到这个时间,比如减小新生代

    G1常用参数

    • -XX:+UseG1GC:开启G1
    • -XX:MaxGCPauseMillis:建议值,G1会尝试调整Young区的块数来达到这个值
    • -XX:GCPauseIntervalMillis:GC的间隔时间
    • -XX:+G1HeapRegionSize:分区大小,建议逐渐增大该值,1 2 4 8 16 32。随着size增加,垃圾的存活时间更长,GC间隔更长,但每次GC的时间也会更长 ZGC做了改进(动态区块大小)
    • G1NewSizePercent:新生代最小比例,默认为5%
    • G1MaxNewSizePercent:新生代最大比例,默认为60%
    • GCTimeRatio:GC时间建议比例,G1会根据这个值调整堆空间
    • ConcGCThreads:线程数量
    • InitiatingHeapOccupancyPercent:启动G1的堆空间占用比例

    常用调优工具

    JDK内置的命令行

    • jps(查看jvm进程信息)
    • jstat(监视jvm运行状态的,比如gc情况、jvm内存情况、类加载情况等)
    • jinfo(查看jvm参数的,也可动态调整)
    • jmap(生成dump文件的,在dump的时候会影响线上服务)
    • jhat(分析dump的,但是一般都将dump导出放到mat上分析)
    • jstack(查看线程的)。

    可视化界面

    QA环境压测

    • JConsole(QA环境压测)
    • VisualVM(QA环境压测)
    • 阿里巴巴开源的arthas(线上调优)

    部分情况分析

    1. 如果有一个系统,内存一直消耗不超过10%,但是观察GC日志,发现FGC总是频繁产生,会是什么引起的?
      检查下系统是否存在System.gc() ;
    2. 线上一个系统跑一段时间就栈溢出了,怎么办 ?
    • 首先检查下是否有死归这种无限递归的程序或者递归方法太多
    • 可以看下栈大小,若太小则可以指定-Xss参数设置栈大小
    1. 系统CPU经常100%,如何调优?

    CPU100%,那肯定是有线程一直在占用着系统资源,所以具体方法如下:

    • 找出哪个进程cpu占用高(top命令)
    • 该进程中的哪个线程cpu占用高(top -Hp $pid命令)
    • 将十进制的tid转化为十六进制(printf %x $tid命令)
    • 导出该线程的堆栈 (jstack pid>pid >pid.log命令)
    • 查找哪个方法(栈帧)消耗时间 (less $pid.log)
    • 可以确认工作线程占比高还是垃圾回收线程占比高
    • 修改代码
    1. 系统内存飙高,如何查找问题?
    • 找出哪个进程内存占用高(top命令)
    • 查看jvm进程号(jps命令)
    • 导出堆内存 (jmap命令生成dump文件,注意:线上系统,内存特别大,jmap执行期间会对进程产生很大影响,甚至卡顿,所以操作前最好先从负载均衡里摘掉。)
    • 分析dump文件 (比如mat软件)

    项目调优

    1. 数据库与SQL优化:一般dba负责数据库优化,比如集群主从等。研发负责SQL优化,比如索引、分库分表等。
    2. 集群优化:让整个集群可以很容易的水平扩容,再比如tomcat/nginx的一些配置优化等。
    3. 硬件升级:选择最合适的硬件,充分利用资源。
    4. 代码优化:安装sonar插件这种检测代码质量的工具。
    5. jvm优化:内存区域大小设置、对象年龄达到次数晋升老年代参数的调整、选择合适的垃圾收集器以及合适的垃圾收集器参数、打印详细的GC日志和oom的时候自动生成dump。
    6. 操作系统优化
    展开全文
  • JVM实战调优

    2021-04-12 16:41:56
    這部分內容是廣大Java開發者都比較熟知的內容,在面試或者看書博客過程中多少有過印象的,但是轉到項目實戰中,例如核心的JVM參數有哪些,如何根據項目評估一套合理的JVM參數,在項目上線後如何根據業務優化JVM配置...

    目录

    一、JVM内存相关参数

    二、新系统上线如何规划容量

    三、垃圾回收器的选择

    四、CMS回收器

    五、G1垃圾回收器

    六、调优总结


    Java程序运行在Java虚拟机之上,JVM管理了整个程序的内存分配和使用,负责对象的整个生命周期。這部分內容是廣大Java開發者都比較熟知的內容,在面試或者看書博客過程中多少有過印象的,但是轉到項目實戰中,例如核心的JVM參數有哪些,如何根據項目評估一套合理的JVM參數,在項目上線後如何根據業務優化JVM配置,碰到GC頻繁該如何分析解決等等實際問題,就基本沒有方法了,如果盲目上網去找JVM優化的文章大部分只說參數調優不基於背景,基本是盲人摸象無法把握住關鍵問題,這篇文章即是對JVM實戰和優化進行一個总结

    篇章大纲图:

    一、JVM内存相关参数

    1.JVM内存参数的权衡

    首先,JVM最重要最核心的参数是去评估内存和分配,第一步需要指定堆内存的大小,这个是系统上线必须要做的,-Xms 初始堆大小,-Xmx 最大堆大小,后台Java服务中一般都指定为系统内存的一半,过大会佔用服务器的系统资源,过小则无法发挥JVM的最佳性能。
    其次需要指定-Xmn新生代的大小,这个参数非常关键,灵活度很大,虽然sun官方推荐为3/8大小,但是要根据业务场景来定,针对于无状态或者轻状态服务(现在最常见的业务系统如Web应用)来说,一般新生代甚至可以给到堆内存的3/4大小;而对于有状态服务(常见如IM服务、网关接入层等系统)新生代可以按照默认比例1/3来设置。服务有状态,则意味著会有更多的本地缓存和会话状态信息常驻内存,应为要给老年代设置更大的空间来存放这些对象。
    最后是设置-Xss栈内存大小,设置单个线程栈大小,默认值和JDK版本、系统有关,一般默认512~1024kb。一个后台服务如果常驻线程有几百个,那麽栈内存这边也会佔用了几百M的大小。

    2.如何设置JVM参数

    如果在IDEA中调试JVM参数,只需要打开项目的Configuration中,对VM Options进行设置即可:

    如果在Linux环境中调试JVM参数,需要在啓动Java进程的时候,加入到啓动命令中:

    [root@LOCAL~]#java -Xmx512m -Xms512m -Xmn256m -Xss1m –jar hello.jar

    服务啓动后,在日志的第一行就会打印jvm参数相关信息:可以验证啓动后的jvm参数是否设置成功!

    二、新系统上线如何规划容量

    1.套路总结

    任何新的业务系统在上线以前都需要去估算服务器配置和JVM的内存参数,这个容量与资源规划并不仅仅是系统架构师的随意估算的,需要根据系统所在业务场景去估算,推断出来一个系统运行模型,评估JVM性能和GC频率等等指标。以下是我结合大牛经验以及自身实践来总结出来的一个建模步骤:

    • 计算业务系统每秒钟创建的对象会佔用多大的内存空间,然后计算集群下的每个系统每秒的内存佔用空间(对象创建速度)
    • 设置一个机器配置,估算新生代的空间,比较不同新生代大小之下,多久触发一次MinorGC。
    • 为了避免频繁GC,就可以重新估算需要多少机器配置,部署多少台机器,给JVM多大内存空间,新生代多大空间。
    • 根据这套配置,基本可以推算出整个系统的运行模型,每秒创建多少对象,1s以后成为垃圾,系统运行多久新生代会触发一次GC,频率多高。

    2.套路实战——以登录系统为例

    有些同学看到这些步骤还是发憷,说的好像是那麽回事,一到实际项目中到底怎麽做我还是不知道!光说不练假把式,这裡就以登录系统为例模拟一下推演过程:

    • 假设每天100w次登陆请求,登陆峰值在早上,预估峰值时期每秒100次登陆请求。
    • 假设部署3台服务器,每台机器每秒处理30次登陆请求,假设一个登陆请求需要处理1秒钟,JVM新生代里每秒就要生成30个登陆对象,1s之后请求完毕这些对象成为了垃圾。
    • 一个登陆请求对象假设20个字段,一个对象估算500字节,30个登陆佔用大约15kb,考虑到RPC和DB操作,网络通信、写库、写缓存一顿操作下来,可以扩大到20-50倍,大约1s产生几百k-1M数据。
    • 假设2C4G机器部署,分配2G堆内存,新生代则只有几百M,按照1s1M的垃圾产生速度,几百秒就会触发一次MinorGC了。
    • 假设4C8G机器部署,分配4G堆内存,新生代分配2G,如此需要几个小时才会触发一次MinorGC。

    到这裡,可以粗略的推断出来一个每天100w次请求的登录系统,按照4C8G的3实例集群配置,分配4G堆内存、2G新生代的JVM,可以保障系统的一个正常负载。基本上把一个新系统的资源评估了出来,所以搭建新系统要每个实例需要多少容量多少配置,集群配置多少个实例等等这些,并不是拍拍脑袋和胸脯就可以决定的下来的。

    三、垃圾回收器的选择

    1.吞吐量还是响应时间

    首先引入两个概念:吞吐量和低延迟
    吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间)
    响应时间 = 平均每次的GC的耗时

    通常,吞吐优先还是响应优先这个在JVM中是一个两难之选。堆内存增大,gc一次能处理的数量变大,吞吐量大;但是gc一次的时间会变长,导致后面排队的线程等待时间变长;相反,如果堆内存小,gc一次时间短,排队等待的线程等待时间变短,延迟减少,但一次请求的数量变小(并不绝对符合)。无法同时兼顾,是吞吐优先还是响应优先,这是一个需要权衡的问题。

    2.垃圾回收器设计上的考量

    • JVM在GC时不允许一边垃圾回收,一边还创建新对象(就像不能一边打扫卫生,还在一边扔垃圾)。

    • JVM需要一段Stop the world的暂停时间,而STW会造成系统短暂停顿不能处理任何请求;

    • 新生代收集频率高,性能优先,常用复制算法;老年代频次低,空间敏感,避免复制方式。

    • 所有垃圾回收器的涉及目标都是要让GC频率更少,时间更短,减少GC对系统影响!

    3.CMS和G1

    目前主流的垃圾回收器配置是新生代采用ParNew,老年代采用CMS组合的方式,或者是完全采用G1回收器,从未来的趋势来看,G1是官方维护和更为推崇的垃圾回收器。

    业务系统,延迟敏感的推荐CMS;大内存服务,要求高吞吐的,采用G1回收器!下面单独就两款回收器的工作机制和适用场景进行一下说明

    四、CMS回收器

    1.CMS垃圾回收器的工作机制

    CMS主要是针对老年代的回收器,新生代的采用ParNew回收器,工作流程就是上文提到的经典复制算法,在三块区中进行流转回收,只不过采用多线程并行的方式加快了MinorGC速度。老年代是标记-清除,默认会在一次FullGC算法后做整理算法,清理内存碎片。

    优点:并发收集、主打“低延时” 。在最耗时的两个阶段都没有发生STW,而需要STW的阶段都以很快速度完成。
    缺点:1、消耗CPU;2、浮动垃圾;3、内存碎片
    适用场景:重视服务器响应速度,要求系统停顿时间最短。

    2.登录系统的压测前配置

    调优场景以之前的登录系统为例,按照之前容量估算套路,引入性能压测环节,测试同学对登录接口压至1s内60M的对象生成速度,假设只配置了4C8G的机器配置,采用ParNew+CMS的组合回收器,堆内存分配4g,线程栈默认1M,初始配置如下:

    -Xms4g –Xmx4g –Xmn1536m -Xss1m -XX:+UseConcMarkSweepGC

    划分Eden和Surviror大小,如按照默认-XX:SurvivorRatio=8分配规则,基于CMS的JVM运行模型粗略计算如下:

    基本上,可以看到20S后Eden区就满了,此时再运行的时候对象已经无法分配,会触发MinorGC,假设在这次GC后S1装入100M,马上过20S又会触发一次MinorGC,多出来的100M存活对象+S1区的100M已经无法顺利放入到S2区,此时就会触发JVM的动态年龄机制,将一批100M左右的对象推到老年代保存,持续运行一段时间,系统可能一个小时候内就会触发一次FullGC。

    3.基于CMS的调优思路

    首先采取上调Survior区容量策略:新生代划2g,维持E:S1:S2=8:1:1,此时Eden=1.6G,S=200M。60M/S速率,25s触发MinorGC,回收的垃圾超过200M才触发进入老年代,对象进入老年代的几率大大降低,短命对象在几次minorGC后就释放掉了。

    此时的JVM配置如下:

    -Xms4g –Xmx4g –Xmn2g -Xss1m -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC

    然后再下调晋升老年代年龄,默认为15——当躲过15次MinorGC后,可进入老年代;可适当调低改值为5~10,让长寿对象应尽快去往属于它的地方,而不是在新生代来回折腾,占用空间,这样可以优化每次MinorGC的耗时。

    -Xms4g –Xmx4g –Xmn2g -Xss1m -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15   -XX:+UseConcMarkSweep

    再选择性的去优化老年代参数:比如老年代默认在标记清除以后会做整理,还可以在CMS的增加GC频次还是增加GC时长上做些取舍,如下是响应优先的参数调优:

    那么最终我们可以得到一个比较适用于自身业务系统的、基于CMS回收器的JVM参数:

    -Xms4g –Xmx4g –Xmn2g -Xss1m -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5   
    -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseCMSInitiatingOccupancyOnly -XX:+Alw

    五、G1垃圾回收器

    1.CMS回收器的不足

    • 服务启动前就需要指定新生代和老年代大小,启动了就不能动态调整了!

    • 新生代和老年代都必须分配独立且连续的一整块内存空间!

    • 所有针对老年代的操作必须扫描整个老年代空间,相同的老年代对象,堆空间越大扫描耗时越长!

    2.G1回收器的设计思路

    G1回收天然的适用于大内存服务器,首先G1将堆内存空间拆分为多个大小相等的Region块,Region的个数默认2048个,配置4g堆内存,每个region的大小就为2M。Region动态的属于老年代或者新生代,上一秒还是分配成新生代,经过回收以后空出来,下一秒有可能被分为老年代区。

    在G1回收器这里已经不需要再提前设置新生代和老年代的大小,但是新生代仍区分Eden和Survivor区。大大降低了JVM参数的调优复杂度,只需配置-XX:MaxGCPauseMillis=n(ms),设置最大GC停顿时间,剩下的交给G1回收器。G1会自动追踪每个region可以回收的大小和预估的时间,最后在真正垃圾回收的时候,尽量把垃圾回收控制在设置的时间范围内,在有限的时间内回收更多的对象。

    所以综合来看,G1主打高吞吐,特别适用多核、大内存服务(如Kafka/ElasticSearch)。

    3.G1的工作机制

    新生代回收:对象优先分配Eden的Region,JVM不停给新生代分配更多的region,直到新生代占堆总大小的60%,触发MinorGC。

    进入老年代对象的条件不变:达到晋升年龄;动态年龄判定;大对象等

    Mix混合回收:当老年代的Region占堆内存的45%以后,触发MixGC,会分阶段多次混合回收新生代和老年代的Region。

    Full GC:MixGC时发现无可用的新Region块了来分配复制的存活对象,立马触发FullGC,停止系统程序,单线程标记、清除和整理,空闲出一批Region,过程很缓慢。

    4.G1的核心调优参数

    G1收集器自身已经有一套预测和调整机制了,因此我们首先的选择是相信它,即调整-XX:MaxGCPauseMillis=N参数,这也符合G1的目的——让GC调优尽量简单!同时也不要自己显式设置新生代的大小(用-Xmn或-XX:NewRatio参数),如果人为干预新生代的大小,会导致目标时间这个参数失效。

    针对-XX:MaxGCPauseMillis来说,参数的设置带有明显的倾向性:
    调低↓:延迟更低,但MinorGC频繁,MixGC回收老年代区减少,增大Full GC的风险。
    调高↑:单次回收更多的对象,但系统整体响应时间也会被拉长。

    针对InitiatingHeapOccupancyPercent来说,调参大小的效果也不一样:
    调低↓:更早触发MixGC,浪费cpu。
    调高↑:堆积过多代回收region,增大FullGC的风险。

    5.G1调优在Kafka集群的应用

    比如日志平台的Kafka集群每秒写入300M数据至内存,broker节点的配置为16C32G,假设堆内存给16g,新生代分配8g,每秒产生对象假设100M左右,差不多一分多钟就会产生一次MinorGC,CMS机制下需要等Eden满了以后,才一次性清理大约8g左右的垃圾对象,差不多会有秒级的STW停顿,如果是老年代的GC延时长则会有十秒级的STW停顿。

    -Xms16g –Xmx16g –Xmn8g -Xss1m -XX:+UseConcMarkSweepGC

    假设采用了G1回收器,适当调低最大耗时,设定MaxGCPauseMillis为100ms,并且适当调低堆使用率阈值,G1就会在允许的响应时间内自动的、多批次的去进行垃圾回收,保证每个STW的时间都不会太长。

    -Xms16g -Xmx16g -Xss1m -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=40

    所以线上的kafka和ES集群,动辄32~64g的大内存,如果让CMS去整块回收十多G乃至几十G的垃圾对象,对于系统而言绝对不利!一般来说,堆内存超过8g的大内存服务器,都更推荐使用G1回收器!

    六、调优总结

    1.系统在上线前的综合调优思路

    • 业务预估:根据预期的并发量、平均每个任务的内存需求大小,然后评估需要几台机器来承载,每台机器需要什么样的配置。

    • 容量预估:根据系统的任务处理速度,然后合理分配Eden、Surivior区大小,老年代的内存大小。

    • 回收器选型:响应优先的系统,建议采用ParNew+CMS回收器;吞吐优先、多核大内存(heap size≥8G)服务,建议采用G1回收器。

    • 优化思路:让短命对象在MinorGC阶段就被回收(同时回收后的存活对象<Survivor区域50%,可控制保留在新生代),长命对象尽早进入老年代,不要在新生代来回复制;尽量减少Full GC的频率,避免FGC系统的影响。

    到目前为止,总结到的调优的过程主要基于上线前的测试验证阶段,所以我们尽量在上线之前,就将机器的JVM参数设置到最优!

    2.一份通用的JVM参数模板

    一般来说,大企业或者架构师团队,都会为项目的业务系统定制一份较为通用的JVM参数模板,但是许多小企业和团队可能就疏于这一块的设计,如果老板某一天突然让你负责定制一个新系统的JVM参数,你上网去搜大量的JVM调优文章或博客,结果发现都是零零散散的、不成体系的JVM参数讲解,根本下不了手,这个时候你就需要一份较为通用的JVM参数模板了,不能保证性能最佳,但是至少能让JVM这一层是稳定可控的,我在这里给大家总结了两份模板:

    1.基于4C8G系统的ParNew+CMS回收器模板(响应优先),新生代大小根据业务灵活调整!

    -Xms4g
    -Xmx4g
    -Xmn2g
    -Xss1m
    -XX:SurvivorRatio=8
    -XX:MaxTenuringThreshold=10
    -XX:+UseConcMarkSweepGC
    -XX:CMSInitiatingOccupancyFraction=70
    -XX:+UseCMSInitiatingOccupancyOnly
    -XX:+AlwaysPreTouch
    -XX:+HeapDumpOnOutOfMemoryError
    -verbose:gc
    -XX:+PrintGCDetails
    -XX:+PrintGCDateStamps
    -XX:+PrintGCTimeStamps
    -Xloggc:gc.log

    2.基于8C16G系统的G1回收器模板(吞吐优先):

    -Xms8g
    -Xmx8g
    -Xss1m
    -XX:+UseG1GC
    -XX:MaxGCPauseMillis=150
    -XX:InitiatingHeapOccupancyPercent=40
    -XX:+HeapDumpOnOutOfMemoryError
    -verbose:gc
    -XX:+PrintGCDetails
    -XX:+PrintGCDateStamps
    -XX:+PrintGCTimeStamps
    -Xloggc:gc.log

    以上两份模板参数,都额外增加了GC日志打印、OOM自动dump等配置内容。

    这篇文章的最后,再多说几句啊,虽然本文主题是JVM实战与调优,但需知JVM调优只是一个手段,但并不一定所有问题都可以通过JVM进行调优解决,大多数的Java应用不需要进行JVM优化,我们可以遵循以下的一些原则:

    • 上线之前,应先考虑将机器的JVM参数设置到最优;

    • 减少创建对象的数量(代码层面);

    • 减少使用全局变量和大对象(代码层面);

    • 优先架构调优和代码调优,JVM优化是不得已的手段(代码、架构层面);

    • 分析GC情况优化代码比优化JVM参数更好(代码层面);

    通过以上原则,我们发现,其实最有效的优化手段是架构和代码层面的优化,而JVM优化则是最后不得已的手段,也可以说是对服务器配置的最后一次“压榨”。

    展开全文
  • jvm 实战调优

    2014-05-21 17:10:30
     如果你想做一些性能调优的工作,一定要善于利用一些工具进行关注相应的状态。通过linux命令你可以比较方便的观测到CPU , I/O , network等一些比较外围的状态, 很多时候就已经可以解决大部分的问题。jvm内部的一些...
     
    转至元数据结尾
     
     

     

    记录一下自己常用的linux系统命令,方便以后查阅,发觉记忆越来越不行了

    找到最耗CPU的java线程

    ps命令

    命令:ps -mp pid -o THREAD,tid,time   或者  ps -Lfp pid

    结果展示:

     

    这个命令的作用,主要是可以获取到对应一个进程下的线程的一些信息。 比如你想分析一下一个java进程的一些运行瓶颈点,可以通过该命令找到所有当前Thread的占用CPU的时间,也就是这里的最后一列。

     

    比如这里找到了一个TID : 30834 ,所占用的TIME时间最高。

    通过 printf "%x\n" 30834 首先转化成16进制, 继续通过jstack命令dump出当前的jvm进程的堆栈信息。 通过Grep命令即可以查到对应16进制的线程id信息,很快就可以找到对应最耗CPU的代码快在哪。

    简单的解释下,jstack下这一串线程信息内容: 

     

    Java代码  收藏代码
    1. "DboServiceProcessor-4-thread-295" daemon prio=10 tid=0x00002aab047a9800 nid=0x7d9b waiting on condition [0x0000000046f66000]  

    nid : 对应的linux操作系统下的tid,就是前面转化的16进制数字

    tid: 这个应该是jvm的jmm内存规范中的唯一地址定位,如果你详细分析jvm的一些内存数据时用得上,我自己还没到那种程度,所以先放下

    top命令

    命令:top -Hp pid 

    结果显示:

     

    和前面的效果一下,你可以实时的跟踪并获取指定进程中最耗cpu的线程。 再用前面的方法提取到对应的线程堆栈信息。

     

    判断I/O瓶颈

    mpstat命令

    命令:mpstat -P ALL 1 1000

    结果显示:

     

    注意一下这里面的%iowait列,CPU等待I/O操作所花费的时间。这个值持续很高通常可能是I/O瓶颈所导致的。

    通过这个参数可以比较直观的看出当前的I/O操作是否存在瓶颈

     

    iostat命令

    命令: iostat -m -x 1 1000


     

    同样你可以观察对应的CPU中的%iowait数据,除此之外iostat还提供了一些更详细的I/O状态数据,比如比较重要的有: 

    avgqu-sz :  The average queue length of the requests that were issued to the device. (磁盘队列的请求长度,正常的话2,3比较好。可以和cpu的load一样的理解)

    await : The average time (in milliseconds) for I/O requests issued to the device to be served. (代表一个I/O操作从wait到完成的总时间)

    svctm和%util都是代表处理该I/O请求花费的时间和CPU的时间比例。 判断是否瓶颈时,这两个参数不是主要的

     

    r/s w/s 和 rMB/s  wMB/s 都是代表当前系统处理的I/O的一些状态,前者是我们常说的tps,后者就是吞吐量。这也是评价一个系统的性能指标

     

    pid命令

    命令: pidstat -p pid -u -d -t -w -h 1 1000

     

    结果显示:

     

    相当实用的一个命令,可以基于当个进程分析对应的性能数据,包括CPU,I/O,IR , CS等,可以方便开发者更加精细化的观察系统的运行状态。不过pidstat貌似是在2.6内核的一些较新的版本才有,需要安装sysstat包。

    ubuntu下,可以通过sudo apt-get install sysstat进行安装。

    sar命令

    命令:sar -x pid 1 1000


     

    sar也可以指定对应的pid,关注固定的几个参数,没有pidstat那么强大。 看不到对应的I/O, IR等信息。

    sar的功能可以覆盖mpstat , iostat的相关功能。

    dstat命令

    命令:dstat -y --tcp 1 1000


     

    通过dstat --tcp可以比较方便的看到当前的tcp的各种状态,不需要每次netstat -nat去看

     

    其他命令

    netstat -natp  :  查看对应的网络链接,关注下Recv-Q , Send-Q , State。

    lsof -p pid :  查找对应pid的文件句柄

    lsof -i : 80  : 查找对应端口被哪个进程占用

    lsof  /tmp/1.txt :查找对应文件被哪个进程占用

     

    tcpdump / wireshark :抓包分析工具

    jstat / jmap / jstack / jps 等一系列的java监控命令

     

    最后

      如果你想做一些性能调优的工作,一定要善于利用一些工具进行关注相应的状态。通过linux命令你可以比较方便的观测到CPU , I/O , network等一些比较外围的状态, 很多时候就已经可以解决大部分的问题。jvm内部的一些运行状态监控,得需要借助一些特有的工具进行细粒度的观测。 

    展开全文
  • JVM实战调优(一)

    2021-03-29 17:42:43
    基于石化大数据项目 JVM实战调优场景1排查定位解决方案场景2排查定位解决方案 去年交付给客户现场的大数据分析展示平台,在交付初期出现了几个性能问题,今天对问题的排查和处理做一个总结。 该系统主要对一些底层的...

    基于石化大数据项目 JVM实战调优

    去年交付给客户现场的大数据分析展示平台,在交付初期出现了几个性能问题,今天对问题的排查和处理做一个总结。
    该系统主要对一些底层的设备数据做相关性分析处理,然后展示在网页上。系统在开发测试环境都是正常稳定的,客户现场部署后的试用初期也OK,但第二个月工厂开始增加设备后,系统查询分析结果十分缓慢。

    场景1

    查询报表时,数据分析结果返回十分缓慢

    排查定位

    1. 发现数据分析接口返回的时间在10s~30s不等,简直不能忍,初步怀疑数据返回量过大浏览器渲染慢导致, 我打开浏览器控制台,发现数据量很小且做了分页返回,排除;
    2. 进入linux服务器,top 发现有运行web服务的java进程CPU居然一度飙升到100%,内存使用反而很低,于是怀疑某些线程操作阻塞了。赶紧top -h 进程id观察哪个线程cpu占比最高,使用jstacK 线程id > jdump.txt 创建当前时刻的线程快照;
    3. 使用 printf “%x\n” 线程id 为获取该线程的16进制id,在jdump中定位日志发现:大量线程在wating on condition,然后发现整个日志大量wating on同一把锁,于是根据 parking to wait for <0x000000073168d480> 中wait的对象进行查找,看是哪一个拥有该对象的线程在Runnable,于是定位到具体的代码行中;
    4. 发现在查询收率分析数据的时候,会调用python脚本分析数据的相关性在返回(上了锁,python每次分析只能有一个线程在调用(可能有中间数据),否则分析结果会错误),由于现场数据量比较大,执行时间过长,当前锁不释放,导致资源等待;

    解决方案

    优化调用分析结果的逻辑,不做实时计算,定时任务分析每10分钟的相关性数据存在mysql库里,减轻web查询的压力。

    优化后每次查询都在1.5s以内,恢复正常。

    场景2

    系统使用偶尔卡顿,体验不好

    排查定位

    1. 通过top查看cpu正常,不足百分之5%,使用 jstat -gcutil 打印GC日志,发现fullGC十分频繁,且老年代空间总是接近溢出。考虑到触发JVM进行Full GC的情况;
      考虑到触发JVM进行Full GC的情况主要有以下三种:
    • System.gc()方法的调用
    • 老年代空间不足
    • 永生区空间不足
    1. 此刻堆内存占用并不多,考虑是否存在一个大对象,进入到老年代导致fullGC? 为了定位到有大对象的创建存在,使用jmap -histo:live (慎用,会产生一次FullGC)发现了一个 [C 的对象数组占比特别高
    2. 导出整个JVM 中内存信息jmap -dump:format=b,file=文件名 [pid]
    3. 然后使用Jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。
      进入 Heap Histogram界面,查看实例数据最多和占用资源最大的类,并且追溯到工程代码,发现:web前端会轮询后台一个数据实时更新的接口,而接口的实现是先从数据把半年的数据load到java内存中,然后做了一个统计并返回数据。也就意味着每次轮询,都会产生大数组对象了,那么改对象直接就进入老年代,导致老年代空间不足,频繁回收。

    解决方案

    1. 优化代码逻辑,在sql层面做一些合理统计只返回需要的数据load到java中。
    2. JVM启动参数:调整各代的内存比例,提高老年代大小。
      在 -Xmx(堆最大内存)不变的情况下,对-Xmn(年轻代大小)进行一些减少,老年代的最大内存 = 堆内存 - 新生代 最大内存。
      从而提升了老年代的空间。
    3. 基于当前响应时间优先的业务场景,更改老年代垃圾回收算法,从PS+PO的方式改成PS+CMS(并发标记清除,最小停顿时间为目的)方式。

    对于CMS的一些说明:

    CMS是针对老年代进行回收的一款并发、使用标记-清除算法的GC
    CMS有什么用?
    CMS以获取最小停顿时间为目的。
    在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景。
    CMS如何执行?
    总体来说CMS的执行过程可以分为以下几个阶段:
    1 初始标记(STW)
    2 并发标记
    3 并发预清理
    4 重标记(STW)
    5 并发清理
    6 重置
    CMS缺点?
    1.CMS回收器采用的基础算法是Mark-Sweep。所有CMS不会整理、压缩堆空间
    2.CMS需要更多的CPU资源。
    3.CMS需要更大的堆空间。
    4.CMS回收器减少了回收的停顿时间,但是降低了堆空间的利用率。

    至此,系统恢复正常。

    展开全文
  • JVM实战调优 问题描述 某一个项目中有一个文字转语音的服务,使用的是科大讯飞的语音转换服务,需要调用三方服务。因其转换服务是一个耗时操作,官方给的demo使用的是 WebSocket 进行数据转换操作。项目中使用线程池...
  • 在上一篇《JVM原理解惑篇》中已经梳理了主要的JVM的理论基础,广大Java开发者对这部分内容都比较熟悉,平常面试或者看书过程中多少准备的,但是谈到JVM实战调优,例如JVM核心参数有哪些、如何根据项目评估一套合理...
  • 一台4核CPU,8G物理内存,采用什么机制进行部署应用? 采用32位的jdk ,内存空间最大扩展到4G,明显浪费内存机制。因此,我们采用64位的jdk进行应用的环境。 有时候,采用64位jdk,有时候也会卡顿现象,因此,...
  • 但是我发现,现在面试 Java 岗位,无论什么规模的公司,一般面试官面着面着就会问到 JVM 相关的问题,什么线程、内存模型、JVM 运行时内存、垃圾回收与算法、GC 垃圾收集器、JAVA IO/NIO 、JVM 类加载机制等等知识点...
  • JVM调优第一步,了解JVM常用命令行参数 JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html HotSpot参数分类 标准: - 开头,所有的HotSpot都支持 非标准:...
  • 认识并观察GC日志 衡量JVM-GC的两个指标 如何定位JVM运行中的问题 找到Java进程,观察各线程,观察gc情况,查找前20各最多对象的类,导出堆dump文件并对其分析
  • JVM实战】JVM参数调优

    千次阅读 2020-03-30 14:45:24
    文章目录JVM参数调优一、调优基本概念二、常用JVM参数三、GC调优思路 JVM参数调优 一、调优基本概念 在调整性能时,JM有三个组件 堆大小调整 垃圾收集器调整 JIT编译器调整 大多数调优选项都与调整堆大小和选择的...
  • 背景 团队线上的(共享基础服务)用户服务user-server和权限服务user-center某段日子内的FullGC过于频繁,且user-center单次FullGC时间过长(1.5s),导致业务高峰期cpu和...在没有显式设置新生代占比时,JVM对于新生代的

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,396
精华内容 558
关键字:

jvm实战调优