一、查看jvm常用命令
jinfo:可以输出并修改运行时的java 进程的opts。
jps:与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。
jstat:一个极强的监视VM内存工具。可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量。
jmap:打印出某个java进程(使用pid)内存内的所有'对象'的情况(如:产生那些对象,及其数量)。
jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。
需要注意:在使用这些工具前,先用JPS命令获取当前的每个JVM进程号,然后选择要查看的JVM。
二、jinfo
jinfo可以查看设置的jvm的信息
jinfo -flag MaxHeapSize [pid] 能够查看最大堆内存 jinfo -flag ThreadStackSize [pid] jinfo -flags [pid] jinfo -flag UseConcMarkSweepGC [pid] jinfo -flag UseG1GC [pid] jinfo -flag UseParallelGC [pid]
三、查看jvm运行时的参数
1)java -XX:+PrintFlagsFinal -version 得出的结果,如果是 = 表示默认值 := 表示被用户或者jvm修改后的值 2)-XX:+UnlockDiagnosticVMOptions 解锁诊断参数 -XX:+PrintCommandLineFlags 打印命令行参数 3)jps jps这个没什么好说的,在linux里面ps是查看进程,jps就是java的ps,查看java进程 如果执行"jps -l"就能查看整个类名
四、jstat
这个指令用来查看jvm统计信息,主要分以下三类:
1)类装载 jstat -class [pid] 1000 10 这个指令指的是每1秒(1000就是1000ms)查看一次类的装载信息,一共看十次。后面的1000和10可以不要 2)垃圾收集 -gc、-gcutil、-gccause、-gcnew、-gcold 3)JIT编译 jstat -compiler [pid] jstat -printcompilation [pid]
五、jmap
jmap是一个很重要的命令,可以查看jvm内存使用情况。可以分为两点讲解:
1)导出内存映像文件 内存溢出自动导出,设置参数既可: +XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 不用多说,设置内存溢出自动导出还有导出的路径 使用jmap命令手动导出: jmap -dump:format=b,file=heap.hprof [pid] 其中format=b代表用二进制导出 2)查看内存映像文件: 在这里http://www.eclipse.org/mat/downloads.php下载内存分析工具,然后把dump文件导入分析就可以了。
六 、jstack
jstack也是一个很重要的命令,可以查看线程使用情况。这里需要知道现场的几种状态,参考如下:
- NEW状态: The thread has not yet started. - RUNNABLE状态:The thread is executing in the JVM. - BLOCKED状态:The thread is blocked waiting for a monitor lock. - WAITING状态:The thread is waiting indefinitely for another thread to perform a particular action. - TIMED_WAITING状态:The thread is waiting for another thread to perform an action for up to a specified waiting time. - TERMINATED状态:The thread has exited. 状态之间是怎么转换的呢?参考如下: jvm里面查看线程使用情况的命令"jstack [pid]",将得到的线程情况输入一个叫做stack.txt的文件: 这个stack.txt文件能够查看到jvm里面某个id的线程是用来做什么的?如果发生了死锁,在最后也会列举出来。 在linux里面怎么知道线程线上执行的情况呢,哪些线程占用了很大的内存呢? 这时可以用这个命令 "top -p [pid] -H" 就能够看到单个进程里面线程的情况: 通过printf "%x" [pid] 可以将10精致的pid 转换为16进制,转换成16进制有什么用? 因为jstack出来的线程是十六进制的,通过刚刚那个值,就能够在jstack出来的文件里面找到使用内存最多的线程是哪一个线程了。
七、jvisualvm
jvisualvm是一个可视化工具,集成了上面指令的几乎所有功能,但是它更加直观,所以jvisualvm也很重要。它也在jdk目录的bin目录下。监控本地应用很简单,直接打开jvisualvm就能看到有本地的了。下面着重介绍监控远程的:
1)监控远程tomcat 修改tomcat的Catalina.sh 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应用: nohup java -Dcom.sun.management.jmxremote -Djava.rmi.server.hostname=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 test.jar 命令是一样的,但是一定要记住的是这里的192.168.1.54一定是我们的java的应用地址,而不是jvisual的地址!! 记得开放端口, 然后把需要的添加的机器192.168.1.54添加到jvisualvm的"远程"标签里面,然后在“远程“标签里面添加端口在ip后面就可以。
这里说一下监控远程可能会有一点坑,原因如下:
1)首先确保在java应用的机器里面可以使用jvisualvm才可以,也就是在java应用的机器里面调用jvisualvm没有报错(可能只是warning),才可以。
2)可能是jdk版本的问题。有可能确认了多少遍端口和应用的问题,但是就是连不上,所以就要看看是不是jdk版本的问题(也许不是,所以就在需要监控的java应用程序的机器上先试下jvisualvm)
JVM性能优化建议
一、JVM堆内存划分
JDK7及以前的版本:一个对象被创建以后首先被放到Nursery内存中的Eden内 存中,如果存活期超两个Survivor之后就会被转移到长时内存中(Old Generation)中。永久内存中存放着对象的方法、变量等元数据信息。通过如果永久内存不够,就会得到如下错误:Java.lang.OutOfMemoryError: PermGen
JDK8版本:JDK8中把存放元数据中的永久内存从堆内存中移到了本地内存(native memory)中,这样永久内存就不再占用堆内存,它可以通过自动增长来避免JDK7以及前期版本中常见的永久内存错误(java.lang.OutOfMemoryError: PermGen)。JDK8也提供了一个新的设置Matespace内存大小的参数:
-XX:MaxMetaspaceSize=128m
需要注意:如果不设置Matespaces内存大小参数,JVM将会根据一定的策略自动增加本地元内存空间。如果你设置的元内存空间过小,你的应用程序可能得到以下错误:java.lang.OutOfMemoryError: Metadata space
二、JVM参数
-XX 参数被称为不稳定参数,此类参数的设置很容易引起JVM性能上的差异。
1)不稳定参数语法规则
布尔类型
-XX:+<option> '+'表示启用该选项 -XX:-<option> '-'表示关闭该选项
数字类型
-XX:<option>=<number> # 可跟随单位,例如:'m'或'M'表示兆字节;'k'或'K'千字节;'g'或'G'千兆字节。32K与32768是相同大小的。
字符串类型
-XX:<option>=<string> # 通常用于指定一个文件、路径或一系列命令列表。例如:-XX:HeapDumpPath=./dump.core
2)行为选项
选项 | 默认值 | 描述 |
-XX:-AllowUserSignalHandlers | 限于Linux和Solaris默认关闭 | 允许为java进程安装信号处理器。 |
-XX:AltStackSize=16384 | 仅适用于Solaris,从5.0中删除 | 备用信号堆栈大小(以字节为单位) |
-XX:-DisableExplicitGC | 默认关闭 | 禁止在运行期显式地调用 System.gc()。注意:你熟悉的代码里没调用System.gc(),不代表你依赖的框架工具没在使用。 |
-XX:+FailOverToOldVerifier | Java6新引入选项,默认启用 | 如果新的Class校验器检查失败,则使用老的校验器。解决兼容性问题。 关联选项:-XX:+UseSplitVerifier |
-XX:+HandlePromotionFailure | Java1.5以前默认关闭,Java1.6后默认启用 | 新生代收集担保,于年老代预留内存。 |
-XX:+MaxFDLimit | 限于Solaris,默认启用 | 设置java进程可用文件描述符为操作系统允许的最大值。 |
-XX:PreBlockSpin | 默认10 | 控制多线程自旋锁优化的自旋次数 前置选项: -XX:+UseSpinning |
-XX:-RelaxAccessControlCheck | 默认关闭,Java1.6引入 | 在Class校验器中,放松对访问控制的检查。作用与reflection里的setAccessible类似。 |
-XX:+ScavengeBeforeFullGC | 默认启用 | 在Full GC前触发一次Minor GC |
-XX:+UseAltSigs | 限于Solaris 默认启用 |
为了防止与其他发送信号的应用程序冲突,允许使用候补信号替代 SIGUSR1和SIGUSR2。 |
-XX:+UseBoundThreads | 限于Solaris 默认启用 |
绑定所有的用户线程到内核线程。 减少线程进入饥饿状态(得不到任何cpu time)的次数。 |
-XX:-UseConcMarkSweepGC | 默认关闭,Java1.4引入 | 启用CMS低停顿垃圾收集器。 |
-XX:+UseGCOverheadLimit | 默认启用,Java1.6引入 | 限制GC的运行时间。如果GC耗时过长,就抛OutOfMemoryError。 |
-XX:+UseLWPSynchronization | 限于solaris, 默认启用, Java1.4引入 | 使用轻量级进程(内核线程)替换线程同步。 |
-XX:-UseParallelGC | -server时启用, 其他情况下:默认关闭, Java1.4引入 | 为新生代使用并行清除,年老代使用单线程Mark-Sweep-Compact的垃圾收集器。 |
-XX:-UseParallelOldGC | 默认关闭, Java1.5引入 | 为老年代和新生代都使用并行清除的垃圾收集器。开启此选项将自动开启-XX:+UseParallelGC 选项 |
-XX:-UseSerialGC | -client时启用, 默认关闭, Java1.5引入 | 使用串行垃圾收集器。 |
-XX:-UseSpinning | Java1.4.2和1.5需要手动启用, Java1.6默认已启用 | 启用多线程自旋锁优化。关联选项:-XX:PreBlockSpin=10 |
-XX:+UseTLAB | Java1.4.2以前和使用-client选项时:默认关闭, 其余版本默认启用 | 启用线程本地缓存区(Thread Local) |
-XX:+UseSplitVerifier | Java1.5默认关闭, Java1.6默认启用 | 使用新的Class类型校验器 。关联选项: -XX:+FailOverToOldVerifier |
-XX:+UseThreadPriorities | 默认启用 | 使用本地线程的优先级。 |
-XX:+UseVMInterruptibleIO | 限于solaris, 默认启用, Java1.6引入 | 在solaris中,允许运行时中断线程 |
3)性能选项
选项 | 默认值 | 描述 |
-XX:+AggressiveOpts | Java1.5 引入,默认关闭,Java1.6后默认开启 | 开启编译器性能优化。 |
-XX:CompileThreshold=10000 | 默认值:1000 | 通过JIT编译器,将方法编译成机器码的触发阀值,可以理解为调用方法的次数,例如调1000次,将方法编译为机器码。 [-client: 1,500] |
-XX:LargePageSizeInBytes=4m | 默认值:4m,amd64位:2m | 设置堆内存的内存最大值。 |
-XX:MaxHeapFreeRatio=70 | 默认70 | GC后,如果发现空闲堆内存占到整个预估上限值的70%,则收缩预估上限值。 |
-XX:MaxNewSize=size | 1.3.1 Sparc: 32m,1.3.1 x86: 2.5m | 新生代占整个堆内存的最大值。从Java1.4开始, MaxNewSize成为 NewRatio的一个函数 |
-XX:MaxPermSize=64m | Java1.5以后::64 bit VMs会增大预设值的30%,1.4 amd64::96m,1.3.1 -client: 32m,其他默认 64m | Perm(俗称方法区)占整个堆内存的最大值。 |
-XX:MinHeapFreeRatio=40 | 默认值:40 | GC后,如果发现空闲堆内存占到整个预估上限值的40%,则增大上限值。关联选项:-XX:MaxHeapFreeRatio=70 |
-XX:NewRatio=2 | Sparc -client: 8,x86 -server: 8 ,x86 -client: 12 -client: 4 (1.3) 8 (1.3.1+) ,x86: 12 ,其他:2 | 新生代和年老代的堆内存占用比例。 例如2表示新生代占年老代的1/2,占整个堆内存的1/3。 |
-XX:NewSize=2m | 5.0以后: 64 bit Vms 会增大预设值的30%,x86: 1m,x86, 5.0以后: 640k,其他:2.125m | 新生代预估上限的默认值。 |
-XX:ReservedCodeCacheSize=32m | Solaris 64-bit, amd64, -server x86: 48m ,1.5.0_06之前, Solaris 64-bit ,amd64: 1024m ,其他:32m | 设置代码缓存的最大值,编译时用。 |
-XX:SurvivorRatio=8 | Solaris amd64: 6 ,Sparc in 1.3.1: 25 ,Solaris platforms 5.0以前: 32 ,其他:8 | Eden与Survivor的占用比例。例如8表示,一个survivor区占用 1/8 的Eden内存,即1/10的新生代内存,为什么不是1/9? 因为我们的新生代有2个survivor,即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 bit: 1024 Linux amd64: 1024 (5.0 以前 0) ,其他:512. | 线程堆栈大小, |
-XX:+UseBiasedLocking | Java1.5 update 6后引入,默认关闭。Java1.6默认启用。 | 启用偏向锁 |
-XX:+UseFastAccessorMethods | 默认启用 | 优化原始类型的getter方法性能。 |
-XX:-UseISM | 默认启用 | 启用solaris的ISM |
-XX:+UseLargePages | Java1.5 update 5后引入,默认关闭,Java1.6默认启用 | 启用大内存分页。关联选项:-XX:LargePageSizeInBytes=4m |
-XX:+UseMPSS | Java1.4.1 之前默认关闭,其他版本默认启用 | 启用solaris的MPSS,不能与ISM同时使用。 |
-XX:+UseStringCache | 默认开启 | 缓存常用字符串。 |
-XX:AllocatePrefetchLines=1 | 默认值:1 | 在使用JIT生成的预读取指令分配对象后读取的缓存行数。如果上次分配的对象是一个实例则默认值是1,如果是一个数组则是3 |
-XX:AllocatePrefetchStyle=1 | 默认值:1 | 预读取指令的生成代码风格,0- 无预读取指令生成 ,1-在每次分配后执行预读取命令 ,2-当预读取指令执行后使用TLAB()分配水印指针来找回入口, |
-XX:+UseCompressedStrings | Java1.6 update 21引入 | 其中,对于不需要16位字符的字符串,可以使用byte[] 而非char[]。对于许多应用,这可以节省内存,但速度较慢(5%-10%) |
-XX:+OptimizeStringConcat | Java1.6 update 20引入 | 在可能的情况下优化字符串连接操作。 |
4)调试选项
选项 | 默认值 | 描述 |
-XX:-CITime | 默认启用 | 打印JIT编译器编译耗时。 |
-XX:ErrorFile=./hs_err_pid.log | Java1.6引入 | 如果JVM crashed,将错误日志输出到指定文件路径。 |
-XX:-ExtendedDTraceProbes | Java6引入,限于solaris,默认关闭 | 启用dtrace诊断 |
-XX:HeapDumpPath=./java_pid.hprof | 默认是java进程启动位置 | 堆内存快照的存储文件路径。 |
-XX:-HeapDumpOnOutOfMemoryError | 默认关闭 | 在java.lang.OutOfMemoryError 异常出现时,输出一个dump.core文件,记录当时的堆内存快照(见 -XX:HeapDumpPath 的描述) |
-XX:OnError=”;” | Java1.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信号)时,打印class柱状图。 jmap -histo pid也实现了相同的功能。 |
-XX:-PrintConcurrentLocks | 默认关闭 | 在thread dump的同时,打印java.util.concurrent的锁状态。jstack -l pid 也同样实现了同样的功能。 |
-XX:-PrintCommandLineFlags | Java1.5 引入,默认关闭 | Java启动时,往stdout打印当前启用的非稳态jvm options。 例如:-XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:+DoEscapeAnalysis |
-XX:-PrintCompilation | 默认关闭 | 往stdout打印方法被JIT编译时的信息。 |
-XX:-PrintGC | 默认关闭 | 开启GC日志打印。显示结果例如: [Full GC 131115K->7482K(1015808K), 0.1633180 secs] ,该选项可通过com.sun.management.HotSpotDiagnosticMXBean API 和 jconsole 动态启用。 |
-XX:-PrintGCDetails | Java1.4引入,默认关闭 | 打印GC回收的详细信息。 显示结果例如: [Full GC (System) [Tenured: 0K->2394K(466048K), 0.0624140 secs] 30822K->2394K(518464K), [Perm : 10443K->10443K(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.0599570 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表示在第1和2次GC后存活的对象大小。 |
-XX:-TraceClassLoading | 默认关闭 | 打印class装载信息到stdout。记Loaded状态。 例如: [Loaded java.lang.Object from /opt/taobao/install/jdk1.6.0_07/jre/lib/rt.jar] |
-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 java.util.HashMapEntryHashMap.java:209<br>说明HashMap类的209行引用了静态类java.util.HashMapEntryHashMap.java:209<br>说明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=<filename>指定的文件) -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=<filename> 使用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
catalina.sh(只运行一个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)即可。