文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JVM常用参数调优方法是什么

2023-06-02 14:07

关注

本篇内容介绍了“JVM常用参数调优方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

对于调优这个事情来说,一般就是三个过程:

Java调优也不外乎这三步。

此外,本文所讲的性能分析、调优等是抛开以下因素的:

调优准备

调优是需要做好准备工作的,毕竟每一个应用的业务目标都不尽相同,性能瓶颈也不会总在同一个点上。在业务应用层面,我们需要:

性能分析

在系统层面能够影响应用性能的一般包括三个因素:CPU、内存和IO,可以从这三方面进行程序的性能瓶颈分析。

CPU分析

当程序响应变慢的时候,首先使用top、vmstat、ps等命令查看系统的cpu使用率是否有异常,从而可以判断出是否是cpu繁忙造成的性能问题。其中,主要通过us(用户进程所占的%)这个数据来看异常的进程信息。当us接近100%甚至更高时,可以确定是cpu繁忙造成的响应缓慢。一般说来,cpu繁忙的原因有以下几个:

确定好cpu使用率最高的进程之后就可以使用jstack来打印出异常进程的堆栈信息:

jstack [pid]

JVM常用参数调优方法是什么

接下来需要注意的一点是,Linux下所有线程最终还是以轻量级进程的形式存在系统中的,而使用jstack只能打印出进程的信息,这些信息里面包含了此进程下面所有线程(轻量级进程-LWP)的堆栈信息。因此,进一步的需要确定是哪一个线程耗费了大量CPU,此时可以使用top -p [processId] -H来查看,也可以直接通过ps -Le来显示所有进程,包括LWP的资源耗费信息。最后,通过在jstack的输出文件中查找对应的LWP的id即可以定位到相应的堆栈信息。其中需要注意的是线程的状态:RUNNABLE、WAITING等。对于Runnable的进程需要注意是否有耗费cpu的计算。对于Waiting的线程一般是锁的等待操作。

也可以使用jstat来查看对应进程的gc信息,以判断是否是gc造成了cpu繁忙。

jstat -gcutil [pid]

JVM常用参数调优方法是什么

还可以通过vmstat,通过观察内核状态的上下文切换(cs)次数,来判断是否是上下文切换造成的cpu繁忙。

vmstat 1 5

JVM常用参数调优方法是什么

此外,有时候可能会由jit引起一些cpu飚高的情形,如大量方法编译等。这里可以使用-XX:+PrintCompilation这个参数输出jit编译情况,以排查jit编译引起的cpu问题。

内存分析

对Java应用来说,内存主要是由堆外内存和堆内内存组成。

  1. 堆外内存

    堆外内存主要是JNI、Deflater/Inflater、DirectByteBuffer(nio中会用到)使用的。对于这种堆外内存的分析,还是需要先通过vmstat、sar、top、pidstat(这里的sar,pidstat以及iostat都是sysstat软件套件的一部分,需要单独安装)等查看swap和物理内存的消耗状况再做判断的。此外,对于JNI、Deflater这种调用可以通过Google-preftools来追踪资源使用状况。

  2. 堆内内存

    此部分内存为Java应用主要的内存区域。通常与这部分内存性能相关的有:

    以上使用不当很容易造成:

    排查堆内存问题的常用工具是jmap,是jdk自带的。一些常用用法如下:

    此外,不管是使用jmap还是在OOM时产生的dump文件,可以使用Eclipse的MAT(MEMORY ANALYZER TOOL)来分析,可以看到具体的堆栈和内存中对象的信息。当然jdk自带的jhat也能够查看dump文件(启动web端口供开发者使用浏览器浏览堆内对象的信息)。此外,VisualVM也能够打开hprof文件,使用它的heap walker查看堆内存信息。

    JVM常用参数调优方法是什么

    • 查看jvm内存使用状况:jmap -heap

    • 查看jvm内存存活的对象:jmap -histo:live

    • 把heap里所有对象都dump下来,无论对象是死是活:jmap -dump:format=b,file=xxx.hprof

    • 先做一次full GC,再dump,只包含仍然存活的对象信息:jmap -dump:format=b,live,file=xxx.hprof

    • Heap space:堆内存不足

    • PermGen space:永久代内存不足

    • Native thread:本地线程没有足够内存可分配

    • 频繁GC -> Stop the world,使你的应用响应变慢

    • OOM,直接造成内存溢出错误使得程序退出。OOM又可以分为以下几种:

    • 创建的对象:这个是存储在堆中的,需要控制好对象的数量和大小,尤其是大的对象很容易进入老年代

    • 全局集合:全局集合通常是生命周期比较长的,因此需要特别注意全局集合的使用

    • 缓存:缓存选用的数据结构不同,会很大程序影响内存的大小和gc

    • ClassLoader:主要是动态加载类容易造成永久代内存不足

    • 多线程:线程分配会占用本地内存,过多的线程也会造成内存不足

IO分析

通常与应用性能相关的包括:文件IO和网络IO。

  1. 文件IO

    可以使用系统工具pidstat、iostat、vmstat来查看io的状况。这里可以看一张使用vmstat的结果图。

    JVM常用参数调优方法是什么

    这里主要注意bi和bo这两个值,分别表示块设备每秒接收的块数量和块设备每秒发送的块数量,由此可以判定io繁忙状况。进一步的可以通过使用strace工具定位对文件io的系统调用。通常,造成文件io性能差的原因不外乎:

    • 大量的随机读写

    • 设备慢

    • 文件太大

  2. 网络IO

    查看网络io状况,一般使用的是netstat工具。可以查看所有连接的状况、数目、端口信息等。例如:当time_wait或者close_wait连接过多时,会影响应用的相应速度。

     netstat -anp

    JVM常用参数调优方法是什么

    此外,还可以使用tcpdump来具体分析网络io的数据。当然,tcpdump出的文件直接打开是一堆二进制的数据,可以使用wireshark阅读具体的连接以及其中数据的内容。

     tcpdump -i eth0 -w tmp.cap -tnn dst port 8080 #监听8080端口的网络请求并打印日志到tmp.cap中

    还可以通过查看/proc/interrupts来获取当前系统使用的中断的情况。

    JVM常用参数调优方法是什么

    各个列依次是:

     irq的序号, 在各自cpu上发生中断的次数,可编程中断控制器,设备名称(request_irq的dev_name字段)

    通过查看网卡设备的终端情况可以判断网络io的状况。

其他分析工具

上面分别针对CPU、内存以及IO讲了一些系统/JDK自带的分析工具。除此之外,还有一些综合分析工具或者框架可以更加方便我们对Java应用性能的排查、分析、定位等。

性能调优

与性能分析相对应,性能调优同样分为三部分。

CPU调优

此外,使用多线程的时候,还需要注意以下几点:

内存调优

内存的调优主要就是对jvm的调优。

其中,对于第一点,具体的还有一点建议:

此外,较小堆引起的碎片问题:因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现“碎片”,如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现“碎片”,可能需要进行如下配置:-XX:+UseCMSCompactAtFullCollection,使用并发收集器时,开启对年老代的压缩。同时使用-XX:CMSFullGCsBeforeCompaction=xx设置多少次Full GC后,对年老代进行压缩。

其余对于jvm的优化问题可见后面JVM参数进阶一节。

代码上,也需要注意:

IO调优

文件IO上需要注意:

网络IO上需要注意:

其他优化建议

此外,jdk7、8在jvm的性能上做了一些增强:

此外,网上还有很多过时的建议,不要再盲目跟随:

JVM参数进阶

jvm的参数设置一直是比较理不清的地方,很多时候都搞不清都有哪些参数可以配置,参数是什么意思,为什么要这么配置等。这里主要针对这些做一些常识性的说明以及对一些容易让人进入陷阱的参数做一些解释。

以下所有都是针对Oracle/Sun JDK 6来讲

  1. 启动参数默认值

    Java有很多的启动参数,而且很多版本都并不一样。但是现在网上充斥着各种资料,如果不加辨别的全部使用,很多是没有效果或者本来就是默认值的。一般的,我们可以通过使用java -XX:+PrintFlagsInitial来查看所有可以设置的参数以及其默认值。也可以在程序启动的时候加入-XX:+PrintCommandLineFlags来查看与默认值不相同的启动参数。如果想查看所有启动参数(包括和默认值相同的),可以使用-XX:+PrintFlagsFinal。 JVM常用参数调优方法是什么 JVM常用参数调优方法是什么

    输出里“=”表示使用的是初始默认值,而“:=”表示使用的不是初始默认值,可能是命令行传进来的参数、配置文件里的参数或者是ergonomics自动选择了别的值。

    此外,还可以使用jinfo命令显示启动的参数。

    这里需要指出的是,当你配置jvm参数时,最好是先通过以上命令查看对应参数的默认值再确定是否需要设置。也最好不要配置你搞不清用途的参数,毕竟默认值的设置是有它的合理之处的。

    • jinfo -flags [pid] #查看目前启动使用的有效参数

    • jinfo -flag [flagName] [pid] #查看对应参数的值

  2. 动态设置参数

    当Java应用启动后,定位到了是GC造成的性能问题,但是你启动的时候并没有加入打印gc的参数,很多时候的做法就是重新加参数然后重启应用。但这样会造成一定时间的服务不可用。最佳的做法是能够在不重启应用的情况下,动态设置参数。使用jinfo可以做到这一点(本质上还是基于jmx的)。

     jinfo -flag [+/-][flagName] [pid] #启用/禁止某个参数 jinfo -flag [flagName=value] [pid] #设置某个参数

    对于上述的gc的情况,就可以使用以下命令打开heap dump并设置dump路径。

     jinfo -flag +HeapDumpBeforeFullGC [pid]  jinfo -flag +HeapDumpAfterFullGC [pid] jinfo -flag HeapDumpPath=/home/dump/dir [pid]

    同样的也可以动态关闭。

     jinfo -flag -HeapDumpBeforeFullGC [pid]  jinfo -flag -HeapDumpAfterFullGC [pid]

    其他的参数设置类似。

  3. -verbose:gc 与 -XX:+PrintGCDetails

    很多gc推荐设置都同时设置了这两个参数,其实,只要打开了-XX:+PrintGCDetails,前面的选项也会同时打开,无须重复设置。

  4. -XX:+DisableExplicitGC

    这个参数的作用就是使得system.gc变为空调用,很多推荐设置里面都是建议开启的。但是,如果你用到了NIO或者其他使用到堆外内存的情况,使用此选项会造成oom。可以用XX:+ExplicitGCInvokesConcurrent或XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses(配合CMS使用,使得system.gc触发一次并发gc)代替。

    此外,还有一个比较有意思的地方。如果你不设置此选项的话,当你使用了RMI的时候,会周期性地来一次full gc。这个现象是由于分布式gc造成的,为RMI服务。

  5. 此参数是设置的堆外内存的上限值。当不设置的时候为-1,此值为-Xmx减去一个survivor space的预留大小。

  6. 由于遗留原因,作用相同的参数

    • -Xss 与 -XX:ThreadStackSize

    • -Xmn 与 -XX:NewSize,此外这里需要注意的是设置了-Xmn的话,NewRatio就没作用了。

  7. -XX:MaxTenuringThreshold

    使用工具查看此值默认值为15,但是选择了CMS的时候,此值会变成4。当此值设置为0时,所有eden里的活对象在经历第一次minor GC的时候就会直接晋升到old gen,survivor space直接就没用。还有值得注意的一点,当使用并行回收器时,此值是没有作用的,并行回收器默认是自动调整这些参数以求达到吞吐量最大的。此外,即使是使用CMS等回收器,晋升到老年代的age也不是不变的,当某一age的对象的大小达到年轻代的50%时,这个age会被动态调整为晋升年龄。

  8. -XX:HeapDumpPath

    使用此参数可以指定-XX:+HeapDumpBeforeFullGC、-XX:+HeapDumpAfterFullGC、-XX:+HeapDumpOnOutOfMemoryError触发heap dump文件的存储位置。

  9. -XX:+UseAdaptiveSizePolicy

    此参数在并行回收器时是默认开启的,会根据应用运行状况做自我调整,如MaxTenuringThreshold、survivor区大小等。其中第一次晋升老年代的年龄以InitialTenuringThreshold(默认为7)开始,后续会自动调整。如果希望跟踪每次minor GC后新的存活周期的阈值,可在启动参数上增加:-XX:+PrintTenuringDistribution。如果想要可以配置这些参数,可以关闭此选项,但paralle的性能很难达到最佳。其他垃圾回收期则慎重开启此开关。

“JVM常用参数调优方法是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     801人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     348人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     311人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     432人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     220人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯