【实践出真知】JVM调优
对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数。
[1] JVM在内存调优方面
JVM在内存调优方面,提供了几个常用的命令,分别为jps,jinfo,jstack,jmap以及jstat命令。分别介绍如下:
-
jps:主要用来输出JVM中运行的进程状态信息,一般使用jps命令来查看进程的状态信息,包括JVM启动参数等。
-
jinfo:主要用来观察进程运行环境参数等信息。
-
jstack:主要用来查看某个Java进程内的线程堆栈信息。jstack pid 可以看到当前进程中各个线程的状态信息,包括其持有的锁和等待的锁。
-
jmap:用来查看堆内存使用状况。jmap -heap pid可以看到当前进程的堆信息和使用的GC收集器,包括年轻代和老年代的大小分配等
-
jstat:进行实时命令行的监控,包括堆信息以及实时GC信息等。可以使用jstat -gcutil pid1000来每隔一秒来查看当前的GC信息。
[3] 如何利用监控工具调优?
BTrace
BTrace是一个开源的Java程序动态跟踪工具,它工作的基本原理是通过Hotspot虚拟机的HotSwap技术将跟踪的代码动态替换到被跟踪的Java程序内,以观察程序运行的细节。通过BTrace可以在不修改代码、不重启应用的情况下,动态地查看程序运行细节,方便地对程序进行调试。
JConsole
JConsole是一款JDK内置的图形化性能分析工具,它可以用来连接本地或者远程正在运行的JVM,对运行的Java应用程序的性能及资源消耗情况进行分析和监控,并提供可视化的图表对相关数据进行展现。通过运行bin目录下的JConsole命令,它将自动搜索出本机所有的Java进程,选中其中一个进程双击即可以开始监控,也可以使用远程连接功能,对远端的JVM进程进行监控。
JVisualVM
JVisualVM是一款功能十分强大的“All-in-One”,涵盖了JVM内存消耗监视、性能分析、线程,以及堆转储分析、垃圾回收监视等几乎所有能包含进来的功能,是到目前为止,伴随JDK发布的功能最为强大的运行、监视和故障排查程序。
https://blog.****.net/persistencegoing/article/details/94005517
https://www.iteye.com/blog/agilestyle-2371409
[2] 如何利用监控工具调优?
- 1. 堆信息查看
-
可查看堆空间大小分配(年轻代、年老代、持久代分配)
-
提供即时的垃圾回收功能
-
垃圾监控(长时间监控回收情况)
-
查看堆内类、对象信息查看:数量、类型等
-
对象引用情况查看
- 有了堆信息查看方面的功能,我们一般可以顺利解决以下问题:
-
年老代年轻代大小划分是否合理
-
内存泄漏垃
-
圾回收算法设置是否合理
- 2. 线程监控
线程信息监控:系统线程数量
线程状态监控:各个线程都处在什么样的状态下
Dump 线程详细信息:查看线程内部运行情况
死锁检查
- 3. 热点分析
-
CPU 热点:检查系统哪些方法占用的大量 CPU 时间;
-
内存热点:检查哪些对象在系统中数量最大(一定时间内存活对象和销毁对象一起统计)这两个东西对于系统优化很有帮助。我们可以根据找到的热点,有针对性的进行系统的瓶颈查找和进行系统优化,而不是漫无目的的进行所有代码的优化。
- 4. 快照
快照是系统运行到某一时刻的一个定格。在我们进行调优的时候,不可能用眼睛去跟踪所有系统变化,依赖快照功能,我们就可以进行系统两个不同运行时刻,对象(或类、线程等)的不同,以便快速找到问题。
举例说,我要检查系统进行垃圾回收以后,是否还有该收回的对象被遗漏下来的了。那么,我可以在进行垃圾回收前后,分别进行一次堆情况的快照,然后对比两次快照的对象情况。
- 5. 内存泄露检查
内存泄漏是比较常见的问题,而且解决方法也比较通用,这里可以重点说一下,而线程、热点方面的问题则是具体问题具体分析了。
内存泄漏一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而导致新的资源分配请求无法完成,引起系统错误。内存泄漏对系统危害比较大,因为它可以直接导致系统的崩溃。
[3] JVM 的一些参数?
- 1. 堆设置
-Xms:初始堆大小
-Xmx:最大堆大小
-XX:NewSize=n:设置年轻代大小
-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为 1:3,年轻代占整个年轻代年老代和的 1/4
-XX:SurvivorRatio=n:年轻代中 Eden 区与两个 Survivor 区的比值。注意 Survivor 区有两个。如:3,表示 Eden:Survivor=3:2,一个Survivor区占整个年轻代的 1/5
-XX:MaxPermSize=n:设置持久代大小
- 2. 收集器设置
-XX:+UseSerialGC:设置串行收集器
-XX:+UseParallelGC:设置并行收集器
-XX:+UseParalledlOldGC:设置并行年老代收集器
-XX:+UseConcMarkSweepGC:设置并发收集器
- 3. 垃圾回收统计信息
-XX:+PrintGC:开启打印 gc 信息
-XX:+PrintGCDetails:打印 gc 详细信息
-XX:+PrintGCTimeStamps
-Xloggc:filename
- 4. 并行收集器设置
-XX:ParallelGCThreads=n:设置并行收集器收集时使用的 CPU 数
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比
- 5. 并发收集器设置
-XX:+CMSIncrementalMode:设置为增量模式。适用于单 CPU 情况
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的 CPU 数。并行收集线程数
详细解释:
打开虚拟机给某一个程序加个断点:
当系统遇到一些问题或者异常的时候,我们往往会查看系统日志、JVM堆栈、GC日志,或者查看线程快照、堆转储快照等信息,然后进行一个客观的分析,最后找到问题。而查看这些最常用的就是JVM自带的监控分析工具,存在于JAVA_HOME/bin下面:
JVM自带的监控工具
其中最常用的就是:jps、jstat、jinfo、jmap、jhat、jstack 这6个命令行工具,以及jconsole和jvisualvm两个可视化工具。
jps(JVM Process Status Tool,虚拟机进程监控工具)
这个命令可以列出正在运行的虚拟机进程,并显示虚拟机执行主类名称,以及这些进程的本地虚拟机唯一ID。这个ID被称为本地虚拟机唯一ID(local virtual Machine Identifier,简写为LVMID)。如果你在linux的一台服务器上使用jps得到的LVMID其实就是和ps 命令得到的PID是一样的。
jps的命令格式:jps [options] [hostid],其实使用比较多的参数是:-lv。-v 是输出:虚拟机进程启动时的JVM参数,-l 输出主类的全名,如果进程执行的是jar包,则输出Jar路径。
jstat(JVM Statistics Monitoring Tool,虚拟机统计信息监视工具)
这个命令用于监视虚拟机各种运行状态信息。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,虽然没有GUI图形界面,只是提供了纯文本控制台环境的服务器上,但它是运行期间定位虚拟机性能问题的首选工具。
jstat的命令格式:jstat [option vmid [interval [s | ms] [count ] ] ],命令格式比较复杂,但是有用的也就是几个,我们一般都是登录到服务器上进行查看,不适合用远程的方式查看问题。整个命令格式翻译过来就是:jstat [参数] LVMID [查询的间隔时间] [查询的次数],如果将查询的间隔时间和查询的次数去掉的话,说明只是查询一次。举个例子,例如:需要每250毫秒查询一次进程2764垃圾收集状况,一共查询20次,那命令应当是:jstat -gc 2764 250 20;jstat的参数有很多。
jinfo (Configuration Info for Java,配置信息工具)
这个命令可以实时地查看和调整虚拟机各项参数。
jinfo命令
jmap(Memory Map for Java,内存映像工具)
jmap用于生成堆转存的快照,一般是heapdump或者dump文件。如果不适用jmap命令,可以使用-XX:+HeapDumpOnOutOfMemoryError参数,当虚拟机发生内存溢出的时候可以产生快照。或者使用kill -3 pid也可以产生。jmap的作用并不仅仅是为了获取dump文件,它可以查询finalize执行队列,java堆和永久代的详细信息,如空间使用率,当前用的哪种收集器。
只能在linux下使用:
jmap的命令格式:jmpa [option] vmid
jmap参数
如果想用jmap以二进制的形式输出4577进程的dump文件到本地的test.bin文件中,则命令是:jmap -dump:format=b,file=test.bin 4577
jhat(虚拟机堆转储快照分析工具)
jhat这个工具是用来分析jmap dump出来的文件。由于这个工具功能比较简陋,运行起来也比较耗时,所以这个工具不推荐使用,也不太会使用到。例如分析上面的test.bin,那就直接使用:jhat test.bin 就行了,这样他会在本地启动一个web服务,端口是7000,这样直接访问:127.0.0.1:7000就能看到分析结果了:
jhat的分析结果
jstack:Java堆栈跟踪工具
这个命令用于查看虚拟机当前时刻的线程快照(一般是threaddump 或者 javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。生成线程快照的主要目的是定位线程出现长时间停顿的原因,入线程间死锁、死循环、请求外部资源导致的长时间等待都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情。
命令格式:jstack [option] vmid,主要的option有三个,-F/-l/-m:
jstack
主要是把线程的堆栈信息打印出来查看线程堆栈中是否存在异常的情况,然后根据具体的情况做处理。
作者:wangmin
链接:https://www.jianshu.com/p/b7b705999072
来源:简书
说说 JVM 的堆转储文件以及获取方式
JVM 的堆转储文件(heap dump)是某个时间点、Java 进程的内存快照。包含了当时内存中还没有被 full GC 回收的对象和类信息。
1 文件内容
堆转储文件包含以下内容:
所有对象 - 对象所对应的类、字段、原生数据类型以及引用。
所有类 - Classloader、类名、超类以及静态字段。
垃圾回收器的根 - Java 垃圾回收就是使用它,进行可达性分析,从而判定一个对象是否可以被回收。
线程堆栈与本地变量。
因为堆转储文件没有保存共享信息,所以找不到对象创建者信息。
2 自动生成模式
我们可以在 JVM 中配置 -XX:+HeapDumpOnOutOfMemoryError,这样在发生内存溢出异常(OutOfMemoryError)时,就会在工作目录中,自动生成堆转储文件。
3 手动生成模式
3.1 jmap 命令
jmap -dump:format=b,file=<filename.hprof>
其中的 format=b,表示转储为二进制格式。
file 指定转储文件的路径,后缀为 hprof。
pid 表示进程 ID。
在 windows cmd 中,可以使用命令 tasklist 来查看进程 ID。
3.2 jconsole 控制台
Jconsole (Java Monitoring and Management Console),是 JDK 自带的监控 、管理工具 。
首先双击 ${JDK_HOME}/bin/jconsole.exe,打开进程连接列表,选择我们需要 dump 的进程:
默认是使用 SSL,本地一般不会用到,所以这里直接选择 “不安全的连接”:
连接成功后,就会进入监控概览:
依次选择 MBean → com.sun.management 下 HostSpotDiagnosic 中的 dumpHeap,在 p0 中输入 hprof 文件的导出路径,这样就可以生成堆转储文件啦:
3.3 Eclipse Memory Analyzer
也可以使用 Eclipse Memory Analyzer,直接从进程中生成堆转储文件。打开 Memory Analyzer,点击右上角的 File → Acquire Heap Dump,这时就会打开本地进程列表,我们选择想要 dump 的进程,并指定好堆存储路径:
点击 Next ,就会进入 Heap Dump Provider 参数配置页,在此我们可以配置导出的类型、是否只导出活跃对象、是否压缩以及制定导出路径参数:
个人更喜欢 jmap 命令,简单、清晰。
链接:https://www.jianshu.com/p/f71f46906bd5