当前位置:编程学堂 > 常见JVM命令及性能调优建议【无法创建Java虚拟机】

常见JVM命令及性能调优建议【无法创建Java虚拟机】

  • 发布:2023-09-29 07:35

1。查看常用jvm命令
jinfo:可以输出和修改正在运行的java进程的opts。
jps:与Unix上的ps类似,用于显示本地java进程。可以查看本地运行的多个java程序并显示它们的进程号。
jstat:一款极其强大的虚拟机内存监控工具。可用于监视虚拟机内存中的各种堆和非堆大小以及内存使用情况。
jmap:打印出某个java进程(使用pid)内存中所有‘对象’的状态(如:生成了哪些对象及其数量)。
jconsole:一个ja​​va GUI监控工具,可以以图形形式显示各种数据。并可以通过远程连接监控远程服务器VM。

注意:在使用这些工具之前,首先使用JPS命令获取每个JVM当前的进程号,然后选择要查看的JVM

2。 jinfo
jinfo可以查看集合jvm的信息

jinfo -flag MaxHeapSize [pid] 可以查看最大堆内存
jinfo -flag ThreadStackSize [pid]
jinfo-标志[pid]
jinfo -flag UseConcMarkSweepGC [pid]
jinfo -flag UseG1GC [pid]
jinfo -flag UseParallelGC [pid]

3。检查jvm运行时参数

1) java -XX:+PrintFlagsFinal -版本
得到的结果,如果是
= 表示默认值
:= 代表用户或者jvm修改的值
2) -XX:+UnlockDiagnosticVMOptions 解锁诊断参数
-XX:+PrintCommandLineFlags 打印命令行参数
3) 太平绅士
jps没什么好说的。在Linux中,ps是查看进程的。 jps是java的ps。查看java进程。
如果执行“jps -l”可以查看整个类名

4。jstat
该命令用于查看jvm统计信息,主要分为以下三类:

1) 类加载
jstat级 [pid] 1000 10
该命令是指每隔1秒(1000即1000ms)检查一次类的加载信息,共检查10次。最后 1000 和 10 是可选的。
2)垃圾收集
-gc、-gcutil、-gccause、-gcnew、-gcold
3)即时编译
jstat-编译器[pid]
jstat -printcompilation [pid]

5。 jmap
jmap是一个非常重要的命令,可以检查jvm的内存使用情况。可以分两点来解释:

1) 导出内存镜像文件
自动导出内存溢出,只需设置参数:
+XX:HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./
不用说,设置内存溢出自动导出以及导出路径。
使用jmap命令手动导出:
jmap -dump:format=b,file=heap.hprof [pid]
其中format=b表示以二进制导出
2)查看内存镜像文件:
在这里下载内存分析工具http://www.sychzs.cn/mat/downloads.php,然后导入dump文件进行分析。

6。 jstack
jstack也是一个非常重要的命令,可以检查线程的使用情况。这里需要了解场景的几种状态,请参考以下:

- 新状态:线程尚未启动。
- RUNNABLE 状态:线程正在 JVM 中执行。
- BLOCKED 状态:线程被阻塞等待监视器锁。
- WAITING 状态:线程无限期地等待另一个线程执行特定操作。- TIMED_WAITING 状态:线程正在等待另一个线程执行操作,时间长达指定的等待时间。
- TERMINATED 状态:线程已退出。
如何在状态之间转换?参考如下:
jvm中查看线程使用情况的命令“jstack [pid]”会将获得的线程状态输入到一个名为stack.txt的文件中:
这个stack.txt文件可以看到jvm中某个ID的线程是用来做什么的?如果发生死锁,也会列在最后。
如何知道Linux中线程的在线执行情况?哪些线程占用大量内存?
这时可以使用命令“top -p [pid] -H”来查看单个进程中线程的状态:
您可以使用 printf "%x" [pid] 将 10 个精确的 pid 转换为十六进制。转换成十六进制有什么用?
因为从jstack出来的线程都是16进制的,通过刚才的值,可以找出jstack出来的文件中哪个线程使用内存最多。

7。 jvisualvm
jvisualvm是一个可视化工具,几乎集成了上述指令的所有功能,但更加直观,所以jvisualvm也非常重要。也在jdk目录的bin目录下。监控本地应用程序非常简单。只要打开jvisualvm,你就会看到有本地应用程序。以下重点关注远程监控:

1)监控远程tomcat
修改tomcat的www.sychzs.cn
JAVA_OPTS='-Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=192.168。 1.54'
参数说明:
第一个参数是端口,不用说;
第二个参数不需要SSL验证。链接时不要检查该属性。
第三个参数不需要验证第四个参数是tomcat应用程序的地址。注意,它不是jvisualvm的地址。
2)监控远程java应用程序:
nohupjava
-Dcom.sun.management.jmxremote
-Djava.rmi.server.主机名=192.168.1.54
-Dcom.sun.management.jmxremote.port=12344
-Dcom.sun.management.jmxremote.ssl=false -
Dcom.sun.management.jmxremote.authenticate=false
-Djava.net.preferIPv4Stack=true
-jar 测试.jar
命令是一样的,但是一定要记住,这里的192.168.1.54一定是我们java的应用地址,而不是jvisual的地址! !
记得打开端口,然后将需要的机器192.168.1.54添加到jvisualvm的“remote”标签中,然后在“remote”标签中的ip后面添加端口。

这里提一下,远程监控可能会存在一些坑,原因如下:
1)首先要确保jvisualvm可以在java应用的机器中使用,即没有报错在java应用程序的机器中调用jvisualvm时报告(可能只是警告),仅此而已。
2)可能是jdk版本的问题。有可能端口和应用程序的问题已经确认了好几次了,但是还是无法连接,所以我们需要看看是否是jdk版本的问题(也可能不是,所以在java应用程序所在的机器上尝试jvisualvm)需要监控)

1。 JVM堆内存划分

JDK7及之前版本:对象创建后,首先会被放置在Nursery内存中的Eden内存中。如果生存期超过两个Survivor,就会转移到长期记忆(Old Generation)中。永久内存存储元数据信息,例如对象方法和变量。如果永久内存不够,会出现如下错误: Java.lang.OutOfMemoryError: PermGen
JDK8版本: 在JDK8中,存储元数据的永久内存从堆内存移至了本地内存(本机内存),使永久内存不再占用堆内存。通过自动增长可以避免JDK7及以前版本中常见的永久内存错误(java.lang.OutOfMemoryError: PermGen)。 JDK8还提供了一个新的参数用于设置Matespace内存大小:

-XX:最大元空间大小=128m

注意:如果不设置Matespaces内存大小参数,JVM会按照一定的策略自动增加本地元内存空间。如果您将元数据空间设置得太小,您的应用程序可能会出现以下错误:java.lang.OutOfMemoryError: Metadata space

2。 JVM参数
-XX参数称为不稳定参数。此类参数的设置很容易造成JVM性能的差异。

1)参数语法规则不稳定
布尔类型

-XX:+

数字类型

-XX:

字符串型

-XX:

2) 行为选项

选项默认 描述
-XX:-AllowUserSignalHandlers 仅限于 Linux 和 Solaris。默认关闭 允许为 java 进程安装信号处理程序。
-XX:AltStackSize=16384 仅适用于 Solaris,从 5.0 中删除 备用信号堆栈大小(以字节为单位)
-XX:-禁用显式GC 默认关闭 不要在运行时显式调用 System.gc()。注意:如果你熟悉的代码中没有调用System.gc(),并不意味着你所依赖的框架工具没有被使用。
-XX:+FailOverToOldVerifier Java 6 新引入的选项,默认启用 如果新的类验证器失败,将使用旧的验证器。修复兼容性问题。
关联选项:-XX:+UseSplitVerifier
-XX:+处理促销失败 Java 1.5之前默认关闭,Java 1.6之后默认开启 保证新生代收集,并在老年代保留内存。
-XX:+MaxFDLimit 仅限 Solaris,默认启用 将java进程的可用文件描述符设置为操作系统允许的最大值。
-XX:PreBlockSpin 默认 10 控制多线程自旋锁优化的自旋次数
预选项:
-XX:+UseSpinning
-XX:-RelaxAccessControlCheck 默认关闭,Java 1.6 中引入 在类验证器中,放宽访问控制检查。功能与反射中的setAccessible类似。
-XX:+ScavengeBeforeFullGC 默认启用 在 Full GC 之前触发 Minor GC
-XX:+UseAltSigs 仅在 Solaris 上
默认启用
为了防止与其他发送信号的应用程序发生冲突,允许使用备用信号来代替 SIGUSR1 和 SIGUSR2。
-XX:+UseBoundThreads 仅在 Solaris 上
默认启用
将所有用户线程绑定到内核线程。减少线程进入饥饿状态(没有获得任何 CPU 时间)的次数。
-XX:-UseConcMarkSweepGC 默认关闭,Java 1.4 中引入 启用 CMS 低暂停垃圾收集器。
-XX:+UseGCOverheadLimit 默认启用,在 Java 1.6 中引入 限制GC的运行时间。如果GC时间太长,就会抛出OutOfMemoryError。
-XX:+使用LWPS同步 仅限solaris,默认启用,Java 1.4中引入 用轻量级进程(内核线程)替换线程同步。
-XX:-使用ParallelGC -服务器启用,其他情况:默认关闭,Java 1.4中引入 对年轻代使用并行清理,对老年代使用单线程 Mark-Sweep-Compact 垃圾收集器。
-XX:-使用ParallelOldGC 默认关闭,Java 1.5 中引入对老年代和年轻代使用并行扫描垃圾收集器。启用此选项将自动启用-XX:+UseParallelGC选项
-XX:-UseSerialGC -客户端启用,默认禁用,在 Java 1.5 中引入 使用串行垃圾收集器。
-XX:-使用旋转 Java1.4.2和1.5需要手动启用,Java1.6默认启用 启用多线程自旋锁优化。相关选项:-XX:PreBlockSpin=10
-XX:+使用TLAB Java 1.4.2之前以及使用-client选项时:默认关闭,其他版本默认启用 启用线程本地缓存(Thread Local)
-XX:+UseSplitVerifier Java1.5默认关闭,Java1.6默认启用 使用新的类类型验证器。相关选项:-XX:+FailOverToOldVerifier
-XX:+UseThreadPriorities 默认启用 使用本地线程优先级。
-XX:+UseVMInterruptibleIO 仅限solaris,默认启用,Java1.6中引入 在Solaris 中,线程允许在运行时被中断

3) 性能选项

选项 默认 描述
-XX:+积极选择 Java 1.5中引入,默认关闭,Java 1.6之后默认开启 启用编译器性能优化。
-XX:编译阈值=10000 默认值:1000 通过JIT编译器,将一个方法编译成机器码的触发阈值可以理解为该方法被调用的次数。例如,调用该方法 1,000 次将会将该方法编译为机器代码。 [-客户:1,500]
-XX:LargePageSizeInBytes=4m 默认值:4m,amd64 位:2m 设置堆内存的最大内存大小。
-XX:MaxHeapFreeRatio=70 默认 70 GC后,如果发现空闲堆内存占了整个预估上限的70%,那么预估上限就会被缩小。
-XX:MaxNewSize=尺寸 1.3.1 Sparc:32m,1.3.1 x86:2.5m 新生代占用整个堆内存的最大量。从Java 1.4开始,MaxNewSize成为NewRatio的函数
-XX:MaxPermSize=64m Java 1.5::64位VM之后会增加默认值的30%,1.4 amd64::96m,1.3.1-client:32m,其他默认为64m Perm(俗称方法区)占用整个堆内存的最大值。
-XX:MinHeapFreeRatio=40 默认值:40 GC后,如果发现空闲堆内存占整个预估上限的40%,则增加上限。相关选项:-XX:MaxHeapFreeRatio=70
-XX:新比率=2 Sparc -客户端:8,x86 -服务器:8,x86 -客户端:12 -客户端:4 (1.3) 8 (1.3.1+),x86:12,其他:2新生代与老年代的堆内存使用比例。例如2表示新生代占用老年代的1/2,占整个堆内存的1/3。
-XX:新尺寸=2m 5.0及更高版本:64位Vms将增加默认值的30%,x86:1m,x86、5.0及更高版本:640k,其他:2.125m 新生代预估上限默认值。
-XX:ReservedCodeCacheSize=32m Solaris 64 位,amd64,-server x86:48m,1.5.0_06 之前,Solaris 64 位,amd64:1024m,其他:32m 设置编译期间使用的代码缓存的最大值。
-XX:SurvivorRatio=8 Solaris amd64: 6 ,Sparc 1.3.1: 25 ,Solaris 5.0 之前的平台: 32 ,其他: 8 Eden 和 Survivor 的占用比例。例如8表示survivor区占用Eden内存的1/8,也就是新生代内存的1/10。为什么不是1/9?因为我们新一代有两个幸存者,分别是S1和S22。因此,survivor总共占用新生代内存的2/10,Eden与新生代的比例为8/10。
-XX:TargetSurvivorRatio=50 默认值:50 实际使用的survivor空间比例。默认值为 47%,最大值为 90%。
-XX:ThreadStackSize=512 Sparc:512,Solaris x86:320(5.0 之前的 256),Sparc 64 位:1024 Linux amd64:1024(5.0 之前的 0),其他:512。 线程堆栈大小,
-XX:+UseBiasedLocking Java 1.5 update 6 之后引入,默认关闭。 Java 1.6 中默认启用。 启用偏置锁定
-XX:+UseFastAccessorMethods 默认启用 优化原始类型的 getter 方法的性能。
-XX:-使用ISM 默认启用 启用Solaris 的ISM
-XX:+使用大页面 Java1.5 update 5后引入,默认禁用,Java1.6中默认启用 启用大内存分页。相关选项:-XX:LargePageSizeInBytes=4m
-XX:+使用MPSS Java 1.4.1之前默认关闭,其他版本默认开启 在Solaris 上启用MPSS,并且不能与ISM 同时使用。
-XX:+UseStringCache 默认开启 缓存常用字符串。
-XX:AllocatePrefetchLines=1 默认值:1 使用 JIT 生成的预取指令分配对象后读取的缓存行数。如果最后分配的对象是实例,则默认值为1,如果是数组,则为3
-XX:AllocatePrefetchStyle=1 默认值:1 预取指令的生成代码风格,0-不生成预取指令,1-每次分配后执行预取命令,2-执行预取指令后使用TLAB()分配水印指针。快来找到入口吧
-XX:+使用压缩字符串 在Java1.6更新21中引入其中,对于不需要16位字符的字符串,可以使用byte[]代替char[]。对于许多应用程序来说,这可以节省内存,但速度较慢 (5%-10%)
-XX:+OptimizeStringConcat 在Java1.6更新20中引入 尽可能优化字符串连接操作。

4) 调试选项

中引入
选项 默认 描述
-XX:-CITime 默认启用 打印JIT编译器编译时间。
-XX:ErrorFile=./hs_err_pid.log 在 Java 1.6 中引入 如果JVM崩溃,将错误日志输出到指定文件路径。
-XX:-扩展DTraceProbes Java 6中引入,仅限solaris,默认关闭 启用 dtrace 诊断
-XX:HeapDumpPath=./java_pid.hprof 默认为java进程启动位置 堆内存快照的存储文件路径。
-XX:-HeapDumpOnOutOfMemoryError 默认关闭 当出现java.lang.OutOfMemoryError异常时,输出一个dump.core文件,记录当时的堆内存快照(参见-XX:HeapDumpPath的说明)
-XX:OnError=”\;\” 在 Java 1.4 中引入每当java抛出ERROR时,运行指定的命令行指令集。指令集与OS环境有关。大多数是Linux下的.sh脚本和Windows下的.bat批处理。
-XX:OnOutOfMemoryError=”\;\” 在 Java1.4.2 update 12 和 Java6第一次发生java.lang.OutOfMemoryError时,运行指定的命令行指令集。指令集与OS环境有关。大多数是Linux下的.sh脚本和Windows下的.bat批处理。
-XX:-PrintClassHistogram 默认关闭 在Windows下,当按ctrl-break或在Linux下执行kill -3(发送SIGQUIT信号)时,会打印类直方图。 jmap -histo pid 也实现相同的功能。
-XX:-PrintConcurrentLocks 默认关闭 线程转储时打印java.util.concurrent的锁状态。 jstack -l pid 也实现了同样的功能。
-XX:-PrintCommandLineFlags Java 1.5中引入,默认关闭 当 Java 启动时,将当前启用的不稳定 jvm 选项打印到 stdout。例如:-XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:+DoEscapeAnalysis
-XX:-打印编译 默认关闭 将方法 JIT 编译到 stdout 时打印信息。
-XX:-PrintGC 默认关闭启用 GC 日志打印。显示结果例如:[Full GC 131115K->7482K(1015808K), 0.1633180 secs]。可以通过 com.sun.management.HotSpotDiagnosticMXBean API 和 jconsole 动态启用此选项。
-XX:-PrintGCDetails Java 1.4中引入,默认关闭 打印GC回收的详细信息。显示结果,例如:[完整GC(系统)[tenud:0k-> 2394K(466048K),0.0624140 secs] 30822K-> 2394K(518464k),[倍数:10443K-> 10443K-> 104443K(16384K),0.0625410 SECS] Times: user=0.05 sys=0.01, real=0.06 secs],可以通过 com.sun.management.HotSpotDiagnosticMXBean API 和 jconsole 动态启用此选项。
-XX:-PrintGCTimeStamps 默认关闭 打印GC暂停需要时间。显示结果例如:2.744: [Full GC (System) 2.744: [Tenured: 0K->2441K(466048K), 0.0598400 secs] 31754K->2441K(518464K), [Perm : 10717K->10717K(16384K)], 0。 0 599570 secs ] [Times: user=0.06 sys=0.00, real=0.06 secs] ,可以通过 com.sun.management.HotSpotDiagnosticMXBean API 和 jconsole 动态启用此选项。
-XX:-PrintTenuringDistribution 默认关闭打印对象的生命周期信息。显示结果如: [GC Desired Survivor Size 4653056 bytes, new Threshold 32 (max 32) - Age 1: 2330640 bytes, 2330640 Total - Age 2: 9520 bytes, 2340160 Total 204009K->21850K(515200K), 0.1563482 secs] , Age1 ,2 表示在第一次和第二次 GC 中幸存下来的对象的大小。
-XX:-TraceClassLoading 默认关闭 将类加载信息打印到标准输出。记住已加载状态。例如:[从/opt/taobao/install/jdk1.6.0_07/jre/lib/rt.jar加载java.lang.Object]
-XX:-TraceClassLoadingPreorder 1.4.2引入,默认关闭 按class的引用/依赖顺序打印类装载信息到stdout。不同于 TraceClassLoading,本选项只记 Loading状态。 例如: [Loading java.lang.Object from /home/confsrv/jdk1.6.0_14/jre/lib/rt.jar]
-XX:-TraceClassResolution 1.4.2引入,默认关闭 打印所有静态类,常量的代码引用位置。用于debug。 例如: RESOLVE java.util.HashMap www.sychzs.cn:209
说明HashMap类的209行引用了静态类www.sychzs.cn:209
说明HashMap类的209行引用了静态类java.util.HashMapEntry
-XX:-TraceClassUnloading 默认关闭 打印class的卸载信息到stdout。记Unloaded状态。
-XX:-TraceLoaderConstraints Java1.6 引入,默认关闭 打印class的装载策略变化信息到stdout。装载策略变化是实现classloader隔离/名称空间一致性的关键技术。
-XX:+PerfSaveDataToFile 默认启用 当java进程因java.lang.OutOfMemoryError 异常或crashed 被强制终止后,生成一个堆快照文件。
-XX:ParallelGCThreads=n 默认值:随JVM运行平台不同而异 配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:+UseCompressedOops 32位默认关闭,64位默认启动 使用compressed pointers。这个参数默认在64bit的环境下默认启动,但是如果JVM的内存达到32G后,这个参数就会默认为不启动,因为32G内存后,压缩就没有多大必要了,要管理那么大的内存指针也需要很大的宽度了
-XX:+AlwaysPreTouch 默认关闭 在JVM 初始化时预先对Java堆进行摸底。
-XX:AllocatePrefetchDistance=n 默认值取决于当前JVM 设置 为对象分配设置预取距离。
-XX:InlineSmallCode=n 默认值取决于当前JVM 设置 当编译的代码小于指定的值时,内联编译的代码。
-XX:MaxInlineSize=35 默认值:35 内联方法的最大字节数。
-XX:FreqInlineSize=n 默认值取决于当前JVM 设置 内联频繁执行的方法的最大字节码大小。
-XX:LoopUnrollLimit=n 默认值取决于当前JVM 设置 代表节点数目小于给定值时打开循环体。
-XX:InitialTenuringThreshold=7 默认值:7 设置初始的对象在新生代中最大存活次数。
-XX:MaxTenuringThreshold=n 默认值:15,最大值:15 设置对象在新生代中最大的存活次数,最大值15,并行回收机制默认为15,CMS默认为4。
-Xloggc: 默认关闭 输出GC 详细日志信息至指定文件。
-XX:-UseGCLogFileRotation 默认关闭 开启GC 日志文件切分功能,前置选项 -Xloggc
-XX:NumberOfGClogFiles=1 必须>=1,默认值:1 设置切分GC 日志文件数量,文件命名格式:.0, .1, …, .n-1
-XX:GCLogFileSize=8K 必须>=8K,默认值:8K GC日志文件切分大小。

三、垃圾收集器
1.  串行回收器
1.1)新生代串行回收器
特点
-  它仅仅使用单线程进行垃圾回收
-  它是独占式的垃圾回收
-  进行垃圾回收时, Java应用程序中的线程都需要暂停(Stop-The-World)
-  使用复制算法
-  适合CPU等硬件不是很好的场合

设置参数

-XX:+UseSerialGC   指定新生使用新生代串行收集器和老年代串行收集器, 当以client模式运行时, 它是默认的垃圾收集器

1.2)老年代串行回收器
特点
-  同新生代串行回收器一样, 单线程, 独占式的垃圾回收器
-  通常老年代垃圾回收比新生代回收要更长时间, 所以可能会使应用程序停顿较长时间

设置参数

-XX:+UseSerialGC   新生代, 老年代都使用串行回收器
-XX:+UseParNewGC   新生代使用ParNew回收器, 老年代使用串行回收器
-XX:+UseParallelGC 新生代使用ParallelGC回收器, 老年代使用串行回收器

2.  并行回收器
2.1)新生代ParNew回收器
特点
-  将串行回收多线程化
-  使用复制算法
-  垃圾回收时, 应用程序仍会暂停, 只不过由于是多线程回收, 在多核CPU上,回收效率会高于串行回收器, 反之在单核CPU, 效率会不如串行回收器

设置参数

-XX:+UseParNewGC 新生代使用ParNew回收器, 老年代使用串行回收器
-XX:+UseConcMarkSweepGC 新生代使用ParNew回收器, 老年代使用CMS回收器
-XX:ParallelGCThreads=n 指回ParNew回收器工作时的线程数量, cpu核数小时8时, 其值等于cpu数量, 高于8时,可以使用公式(3+((5*CPU_count)/8))

2.2)新生代ParallelGC回收器
特点
-  同ParNew回收器一样, 不同的地方在于,它非常关注系统的吞吐量(通过参数控制)
-  使用复制算法
-  支持自适应的GC调节策略

设置参数

-XX:+UseParallelGC  新生代用ParallelGC回收器, 老年代使用串行回收器
-XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器系统吞吐量的控制:
-XX:MaxGCPauseMillis=n(单位ms)   设置垃圾回收的最大停顿时间,
-XX:GCTimeRatio=n(n在0-100之间)  设置吞吐量的大小, 假设值为n, 那系统将花费不超过1/(n+1)的时间用于垃圾回收
-XX:+UseAdaptiveSizePolicy  打开自适应GC策略, 在这种模式下, 新生代的大小, eden,survivior的比例, 晋升老年代的对象年龄等参数会被自动调整,以达到堆大小, 吞吐量, 停顿时间之间的平衡点

2.3)老年代ParallelOldGC回收器
特点
-  同新生代的ParallelGC回收器一样, 是属于老年代的关注吞吐量的多线程并发回收器
-  使用标记压缩算法

设置参数

-XX:+UseParallelOldGC  新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器, 是非常关注系统吞吐量的回收器组合, 适合用于对吞吐量要求较高的系统
-XX:ParallelGCThreads=n   指回ParNew回收器工作时的线程数量, cpu核数小时8时, 其值等于cpu数量, 高于8时, 可以使用公式(3+((5*CPU_count)/8))

3.  CMS回收器(Concurrent Mark Sweep,并发标记清除)
3.1)老年代的并发回收器
特点
-  是并发回收, 非独占式的回收器, 大部分时候应用程序不会停止运行
-  针对年老代的回收器
-  使用并发标记清除算法, 因此回收后会有内存碎片, 可以使参数设置进行内存碎片的压缩整理
-  与ParallelGC和ParallelOldGC不同, CMS主要关注系统停顿时间

主要步骤
-  初始标记
-  并发标记
-  预清理
-  重新标记
-  并发清理
-  并发重置

需要注意:初始标记与重新标记是独占系统资源的,不能与用户线程一起执行,而其它阶段则可以与用户线程一起执行

设置参数

-XX:-CMSPrecleaningEnabled  关闭预清理, 不进行预清理, 默认在并发标记后, 会有一个预清理的操作,可减少停顿时间
-XX:+UseConcMarkSweepGC  老年代使用CMS回收器, 新生代使用ParNew回收器
-XX:ConcGCThreads=n  设置并发线程数量,
-XX:ParallelCMSThreads=n  同上, 设置并发线程数量,
-XX:CMSInitiatingOccupancyFraction=n  指定老年代回收阀值, 即当老年代内存使用率达到这个值时, 会执行一次CMS回收,默认值为68, 设置技巧: (Xmx-Xmn)*(100-CMSInitiatingOccupancyFraction)/100)>=Xmn
-XX:+UseCMSCompactAtFullCollection  开启内存碎片的整理, 即当CMS垃圾回收完成后, 进行一次内存碎片整理, 要注意内存碎片的整理并不是并发进行的, 因此可能会引起程序停顿
-XX:CMSFullGCsBeforeCompation=n  用于指定进行多少次CMS回收后, 再进行一次内存压缩
-XX:+CMSParallelRemarkEnabled  在使用UseParNewGC 的情况下, 尽量减少 mark 的时间
-XX:+UseCMSInitiatingOccupancyOnly  表示只有达到阀值时才进行CMS回收
-XX:+CMSConcurrentMTEnabled 当该标志被启用时,并发的CMS阶段将以多线程执行,默认开启
-XX:+CMSIncrementalMode 在增量模式下,CMS 收集器在并发阶段,不会独占整个周期,而会周期性的暂停,唤醒应用线程。收集器把并发阶段工作,划分为片段,安排在次级(minor) 回收之间运行。这对需要低延迟,运行在少量CPU服务器上的应用很有用。

3.2)Class的回收(永久区的回收)
设置参数

-XX:+CMSClassUnloadingEnabled  开启回收Perm区的内存, 默认情况下, 是需要触发一次FullGC
-XX:CMSInitiatingPermOccupancyFraction=n  当永久区占用率达到这个n值时,启动CMS回收, 需上一个参数开启的情况下使用

4. G1回收器JDK1.7后全新的回收器, 用于取代CMS)
4.1)概述
特点
-  独特的垃圾回收策略, 属于分代垃圾回收器
-  使用分区算法, 不要求eden, 年轻代或老年代的空间都连续
-  并行性:回收期间, 可由多个线程同时工作, 有效利用多核cpu资源
-  并发性:与应用程序可交替执行, 部分工作可以和应用程序同时执行
-  分代GC::分代收集器, 同时兼顾年轻代和老年代
-  空间整理:回收过程中, 会进行适当对象移动, 减少空间碎片
-  可预见性:G1可选取部分区域进行回收, 可以缩小回收范围, 减少全局停顿

主要步骤
-  新生代GC
-  并发标记周期

初始标记新生代GC(此时是并行, 应用程序会暂停止) –> 根区域扫描 –> 并发标记 –> 重新标记(此时是并行, 应用程序会暂停止) –> 独占清理(此时应用程序会暂停止) –> 并发清理

-  混合回收

这个阶段即会执行正常的年轻代gc, 也会选取一些被标记的老年代区域进行回收, 同时处理新生代和年老轻

-  若需要,会进行FullGC

混合GC时发生空间不足
在新生代GC时, survivor区和老年代无法容纳幸存对象时
以上两者都会导致一次FullGC产生

设置参数

-XX:+UseG1GC  打开G1收集器开关,
-XX:MaxGCPauseMillis=n  指定目标的最大停顿时间,任何一次停顿时间超过这个值, G1就会尝试调整新生代和老年代的比例, 调整堆大小, 调整晋升年龄
-XX:ParallelGCThreads=n  用于设置并行回收时, GC的工作线程数量
-XX:InitiatingHeapOccpancyPercent=n  指定整个堆的使用率达到多少时, 执行一次并发标记周期, 默认45, 过大会导致并发标记周期迟迟不能启动, 增加FullGC的可能, 过小会导致GC频繁, 会导致应用程序性能有所下降

4.2)参数选项

选项 默认值 描述
-XX:+UseG1GC 默认关闭 使用G1垃圾处理器
-XX:MaxGCPauseMillis=n 默认值:4294967295 设置并行收集最大暂停时间,这是一个理想目标,JVM将尽最大努力来实现它。
-XX:InitiatingHeapOccupancyPercent=n 默认值:45 启动一个并发垃圾收集周期所需要达到的整堆占用比例。这个比例是指整个堆的占用比例而不是某一个代(例如G1),如果这个值是0则代表‘持续做GC’。默认值是45
-XX:NewRatio=n 默认值:2 设置年轻代和年老代的比值。例如:值为3,则表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4。
-XX:SurvivorRatio=n 默认值:8 年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5
-XX:MaxTenuringThreshold=n 默认值:15 设置垃圾最大存活阀值。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。
-XX:ParallelGCThreads=n 默认值:随JVM运行平台不同而异 配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。
-XX:ConcGCThreads=n 默认值:随JVM运行平台不同而异 并行垃圾收集时,使用的线程数。默认值和JVM运行的平台有关。
-XX:G1ReservePercent=n 默认值:10 设置保留用来做假天花板以减少晋升(新生代对象晋升到老生代)失败可能性的堆数目。
-XX:G1HeapRegionSize=n 默认值根据堆大小而定 使用G1垃圾回收器,java堆被划分成统一大小的区块。这个选项设置每个区块的大小。最小值是1Mb,最大值是32Mb。

4.3)其他GC相关的设置
4.3.1)System.gc()

1)禁用System.gc()
-XX:+DisableExplicitGC 禁止程序中调用System.gc(), 加了此参数, 程序若有调用, 返回的空函数调用System.gc()的调用, 会使用FullGC的方式回收整个堆而会忽略CMS或G1等相关回收器
2)System.gc()使用并发回收
-XX:+ExplicitGCCinvokesConcurrent  使用并发方式处理显示的gc, 即开启后, System.gc()这种显示GC才会并发的回收, (CMS, G1)

4.3.2)并行GC前额外触发的新生代GC

1)使用并行回收器 (UseParallelGC或者UseParallelOldGC)时, 会额外先触发一个新生代GC, 目的是尽可能减少停顿时间
2)若不需要这种特性, 可以使用以下参数去除
-XX:-ScavengeBeforeFullGC  即去除在FullGC之前的那次新生代GC, 原本默认值为true 

4.3.3)对象何时进入老年代

1)当对象首次创建时, 会放在新生代的eden区, 若没有GC的介入,会一直在eden区, GC后,是可能进入survivor区或者年老代
2)当对象年龄达到一定的大小 ,就会离开年轻代, 进入老年代, 对象进入老年代的事件称为晋升, 而对象的年龄是由GC的次数决定的,
每一次GC,若对象没有被回收, 则对象的年龄就会加1, 可以使用以下参数来控制新生代对象的最大年龄:
-XX:MaxTenuringThreshold=n 假设值为n , 则新生代的对象最多经历n次GC, 就能晋升到老年代, 但这个必不是晋升的必要条件
-XX:TargetSurvivorRatio=n  用于设置Survivor区的目标使用率,即当survivor区GC后使用率超过这个值, 就可能会使用较小的年龄作为晋升年龄
3)除年龄外, 对象体积也会影响对象的晋升的, 若对象体积太大, 新生代无法容纳这个对象, 则这个对象可能就会直接晋升至老年代, 可通过以下参
数使用对象直接晋升至老年代的阈值, 单位是byte
-XX:PretenureSizeThreshold 即对象的大小大于此值, 就会绕过新生代, 直接在老年代分配, 此参数只对串行回收器以及ParNew回收有效, 而对ParallelGC回收器无效

4.3.4)在TLAB上分配对象(Thread Local Allocation Buffer, 线程本地分配缓存)

TLAB是一个线程专用的内存分配区域, 虚拟机为线程分配空间, 针对于体积不大的对象, 会优先使用TLAB, 这个可以加速对象的分配, TLAB是默认开启的, 若要关闭可以使用以下参数关闭
-XX:-UseTLAB  关闭TLAB
-XX:+UseTLAB  开启TLAB, 默认也是开启的
-XX:+PrintTLAB 观察TALB的使用情况
-XX:TLABRefillWasteFraction=n  设置一个比率n, 而refill_waste的值就是(TLAB_SIZE/n), 即TLAB空间较小, 大对象无法分配在TLAB,所以会直接分配到堆上,TLAB较小也很容易装满, 因此当TLAB的空间不够分配一个新对象, 就会考虑废弃当前TLAB空间还是直接分配到堆上, 就会使用此参数进行判断, 小于refill_waste就允许废弃, 而新建TLAB来分配对象,而大于refill_waste就直接在堆上分配, 默认是64
-XX:+ResizeTLAB  开启TLAB自动调整大小, 默认是开启的, 若要关闭把+号换成-号即可
-XX:TLABSize=n  设置一个TLAB的大小, 前提先关闭TLAB的自动调整

5.  性能调优工具
5.1)jps  (Java Virtual Machine Process Status Tool)
主要用来输出JVM中运行的进程状态信息。语法格式如下:

jps [options] [hostid]
# hostid语法如下:
[protocol:][[//]hostname][:port][/servername]
protocol - 如果protocol及hostname都没有指定,那表示的是与当前环境相关的本地协议,如果指定了hostname却没有指定protocol,那么protocol的默认就是rmi。
hostname - 服务器的IP或者名称,没有指定则表示本机。
port - 远程rmi的端口,如果没有指定则默认为1099。
Servername - 注册到RMI注册中心中的jstatd的名称。
# 如果不指定hostid就默认为当前主机或服务器。
# 命令行参数选项
-q 忽略输出类名、Jar名和传入main方法的参数
-m 输出传入main方法的参数
-l 输出main类或Jar的全限名
-v 输出传入JVM的参数
-V 输出通过标记的文件传递给JVM的参数(.hotspotrc文件,或者是通过参数-XX:Flags=指定的文件)
-J 用于传递jvm选项到由javac调用的java加载器中,例如,“-J-Xms48m”将把启动内存设置为48M,使用-J选项可以非常方便的向基于Java的开发的底层虚拟机应用程序传递参数。

5.2)stack(Java Stack Trace)
主要用来查看某个Java进程内的线程堆栈信息。语法格式如下:

jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
# 命令行参数选项说明如下:
-l 长列表,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
-F 当’jstack [-l] pid’没有相应的时候强制打印栈信息
-h | -help打印帮助信息

jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。

5.3)jmap(Java Memory Map)
jmap用来查看堆内存使用状况,一般结合jhat使用。jmap语法格式如下:(如果运行在64位JVM上,可能需要指定-J-d64命令选项参数)

jmap [option] pid
jmap [option] executable core
jmap [option] [server-id@]remote-hostname-or-ip
# 参数说明
executable 产生core dump的java可执行程序
core 将被打印信息的core dump文件
remote-hostname-or-ip 远程debug服务的主机名或ip
server-id 唯一id,假如一台主机上多个远程debug服务
pid 需要被打印配相信息的java进程id,可以用jps查问
# 基本参数
-dump:[live,]format=b,file= 使用hprof二进制形式,输出jvm的heap内容到文件=. live子选项是可选的,假如指定live选项,那么只输出活的对象到文件
-finalizerinfo 打印正等候回收的对象的信息
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况
-histo[:live] 打印每个class的实例数目,内存占用,类全名信息. VM的内部类名字开头会加上前缀”*”. 如果live子参数加上后,只统计活的对象数量
-permstat 打印classload和jvm heap长久层的信息. 包含每个classloader的名字,活泼性,地址,父classloader和加载的class数量. 另外,内部String的数量和占用内存数也会打印出来
-F 强迫.在pid没有相应的时候使用-dump或者-histo参数. 在这个模式下,live子参数无效
-h | -help 打印辅助信息
-J 传递参数给jmap启动的jvm

5.4)jhat(Java Heap Analysis Tool)
jhat用于对JAVA heap进行离线分析的工具,它可以对不同虚拟机中导出的heap信息文件进行分析

# jmap -dump:format=b,file=dumpFileName pid
jmap -dump:format=b,file=/tmp/dump.dat 21711
jhat -port 9998 /tmp/dump.dat
# 注意如果Dump文件太大,可能需要加上-J-Xmx512m这种参数指定最大堆内存
# 在浏览器中输入主机地址:9998查看

另外,可以使用Eclipse插件MAT(Memory Analyzer Tool)对dump文件进行分析。

5.5)jstat(Java Virtual Machine Statistics Monitoring Tool)
Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:

类的加载及卸载情况
-  查看新生代、老生代及持久代的容量及使用情况
-  查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间
-  查看新生代中Eden区及Survior区中容量及分配情况等

语法:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
generalOption - 单个的常用的命令行选项,如-help, -options, 或 -version。
outputOptions -一个或多个输出选项,由单个的statOption选项组成,可以和-t, -h, and -J等选项配合使用。
statOption 根据jstat统计的维度不同,可以使用如下表中的选项进行不同维度的统计,不同的操作系统支持的选项可能会不一样,可以通过-options选项,查看不同操作系统所支持选项
-h n 用于指定每隔几行就输出列头,如果不指定,默认是只在第一行出现列头。
-J javaOption 用于将给定的javaOption传给java应用程序加载器,例如,“-J-Xms48m”将把启动内存设置为48M
-t n 用于在输出内容的第一列显示时间戳,这个时间戳代表的时JVM开始启动到现在的时间
vmid VM的进程号,即当前运行的java进程号
interval 间隔时间,单位可以是秒或者毫秒,通过指定s或ms确定,默认单位为毫秒
count 打印次数,如果缺省则打印无数次

===统计维度与输出===
1)class 用于查看类加载情况的统计

2)compiler 用于查看HotSpot中即时编译器编译情况的统计

3)gc 用于查看JVM中堆的垃圾收集情况的统计

4)gccapacity 用于查看新生代、老生代及持久代的存储容量情况

5)gccause 用于查看垃圾收集的统计情况(这个和-gcutil选项一样),如果有发生垃圾收集,它还会显示最后一次及当前正在发生垃圾收集的原因。

6)gcnew 用于查看新生代垃圾收集的情况

7)gcnewcapacity 用于查看新生代的存储容量情况

8)gcold 用于查看老生代及持久代发生GC的情况

9)gcoldcapacity 用于查看老生代的容量

10)gcpermcapacity 用于查看持久代的容量

11)gcutil 用于查看新生代、老生代及持代垃圾收集的情况

12)printcompilation HotSpot编译方法的统计

示例

jstat -gc 1618 250 4

5.6)jvisualvm(Java Virtual Machine Monitoring, Troubleshooting, and Profiling Tool)
jvisualvm同jconsole都是一个基于图形化界面的、可以查看本地及远程的JAVA GUI监控工具,Jvisualvm同jconsole的使用方式一样,直接在命令行打入Jvisualvm即可启动,不过Jvisualvm相比,界面更美观一些,数据更实时。

5.7)jconsole
一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。命令行里打 jconsole,选则进程就可以了。

需要注意:在运行jconsole之前,必须要先设置环境变量DISPLAY,否则会报错误,Linux下设置环境变量如下:
export DISPLAY=:0.0

5.8)jprofile
JProfiler是一个需要商业授权的全功能的Java剖析工具(profiler),专用于分析J2SE和J2EE应用程序。

它把CPU、执行绪和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合用途。JProfiler直觉式的GUI让你可以找到效能瓶颈、抓出内存漏失(memory leaks)、并解决执行绪的问题。它让你得以对heap walker作资源回收器的root analysis,可以轻易找出内存漏失;heap快照(snapshot)模式让未被参照(reference)的对象、稍微被参照的对象、或在终结(finalization)队列的对象都会被移除;整合精灵以便剖析浏览器的Java外挂功能。

5.9)jca
Java线程分析工具,专业的线程分析工具兼容sun/oracle JDK dump线程堆,图形化显示线程概括信息,非常容易的定位问题。
jca是一个类工具 启动方法

java -jar jca433.jar

5.10)jinfo命令 (Java Configuration Info)
jinfo可以输出并修改运行时的java 进程的opts。用处比较简单,用于输出JAVA系统参数及命令行参数。用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。

5.11)Jdb命令 (The Java Debugger)
用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试。

5.12)Jstatd命令 (Java Statistics Monitoring Daemon)
jstatd是一个基于RMI(Remove Method Invocation)的服务程序,它用于监控基于HotSpot的JVM中资源的创建及销毁,并且提供了一个远程接口允许远程的监控工具连接到本地的JVM执行命令。

jstatd是基于RMI的,所以在运行jstatd的服务器上必须存在RMI注册中心,如果没有通过选项”-p port”指定要连接的端口,jstatd会尝试连接RMI注册中心的默认端口。后面会谈到如何连接到一个默认的RMI内部注册中心,如何禁止默认的RMI内部注册中心的创建,以及如何启动一个外部注册中心。
参数选项

-nr 如果RMI注册中心没有找到,不会创建一个内部的RMI注册中心。
-p port RMI注册中心的端口号,默认为1099。
-n rminame 默认为JStatRemoteHost;如果同一台主机上同时运行了多个jstatd服务,rminame可以用于唯一确定一个jstatd服务;这里需要注意一下,如果开启了这个选项,那么监控客户端远程连接时,必须同时指定hostid及vmid,才可以唯一确定要连接的服务,这个可以参看jps章节中列出远程服务器上Java进程的示例。
-J 用于传递jvm选项到由javac调用的java加载器中,例如,“-J-Xms48m”将把启动内存设置为48M,使用-J选项可以非常方便的向基于Java的开发的底层虚拟机应用程序传递参数。

安全性
jstatd服务只能监视具有适当的本地访问权限的JVM,因此jstatd进程与被监控的JVM必须运行在相同的用户权限中。但是有一些特殊的用户权限,如基于UNIX(TM)为系统的root用户,它有权限访问系统中所有JVM的资源,如果jstatd进程运行在这种权限中,那么它可以监视系统中的所有JVM,但是这也带来了额外的安全问题。

示例

# 使用内部RMI注册中心(默认端口是1099),启动jstatd
jstatd -J-Djava.security.policy=jstatd.all.policy
# 使用外部的RMI注册中心,启动jstatd
rmiregistry&jstatd -J-Djava.security.policy=all.policy
# 外部的RMI注册中心来启动jstatd,此注册中心的端口为2020
rmiregistry 2020&jstatd -J-Djava.security.policy=all.policy -p 2020
# 外部的RMI注册中心来启动jstatd,此注册中心的端口为2020,并且绑定到RMI注册中心的名为AlternateJstatdServerName
rmiregistry 2020&jstatd -J-Djava.security.policy=all.policy -p 2020 -n AlternateJstatdServerName
# 禁止内部RMI注册中心的创建
jstatd -J-Djava.security.policy=all.policy -nr
# 开启RMI日记记录,jstatd运行在开启了日志记录功能的RMI注册中
jstatd -J-Djava.security.policy=all.policy -J-Djava.rmi.server.logCalls=true

5.13)httpwatch
网页数据分析工具,对客户端到服务器端的请求,响应数据有效的监控分析。

6. 生产环境示例
6.1)Tomcat7
www.sychzs.cn(只运行一个Tomcat)

# 8G内存
JAVA_OPTS="
-Dfile.encoding=UTF-8
-server
-Djava.awt.headless=true
-Xms6144m
-Xmx6144m
-XX:NewSize=1024m
-XX:MaxNewSize=2048m
-XX:PermSize=512m
-XX:MaxPermSize=512m
-XX:MaxTenuringThreshold=15
-XX:NewRatio=2
-XX:+AggressiveOpts
-XX:+UseBiasedLocking
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+DisableExplicitGC"
# 16G内存(垃圾回收略)
JAVA_OPTS="
-Dfile.encoding=UTF-8
-server
-Xms13312m
-Xmx13312m
-XX:NewSize=3072m
-XX:MaxNewSize=4096m
-XX:PermSize=512m
-XX:MaxPermSize=512m
-XX:MaxTenuringThreshold=10
-XX:NewRatio=2
-XX:+DisableExplicitGC"
# 32G内存(垃圾回收略)
JAVA_OPTS="
-Dfile.encoding=UTF-8
-server
-Xms29696m
-Xmx29696m
-XX:NewSize=6144m
-XX:MaxNewSize=9216m
-XX:PermSize=1024m
-XX:MaxPermSize=1024m
-XX:MaxTenuringThreshold=10
-XX:NewRatio=2
-XX:+DisableExplicitGC"

6.2)Hadoop
建议Hadoop进程的GC参数加上如下选项,很多商业版都默认加上了,这对JDK性能提升有很大帮助

-XX:CMSInitiatingOccupancyFraction=70
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseConcMarkSweepGC
-XX:-CMSConcurrentMTEnabled
-XX:+CMSIncrementalMode
-Djava.net.preferIPv4Stack=true

7. 参考
JDK8中JVM堆内存划分

JDK8引进的JVM参数变化记录
JVM 不稳定参数
java 8 JVM性能优化
Java性能优化攻略详解
Jvm垃圾回收器详细

JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用详解
jps命令 (Java Virtual Machine Process Status Tool)

                                 Could not create the Java virtual machine                                 

一般原因如下:
1)执行程序里的JAVA路径不对造成的!通过"echo $JAVA_HOME"查找出JAVA路径,然后更新程序中的JAVA路径配置即可。
2)JVM参数不对造成(可能是stack size太小)。修改JVM_OPTIONS配置里的JVM参数值即可。
3)jdk版本不兼容导致。调整jdk版本(比如jdk版本过低,调整为高版本的jdk)即可。

相关文章