本文共 14004 字,大约阅读时间需要 46 分钟。
说明XX参数的语法:
所有的XX参数都以”-XX:”开始,但是随后的语法不同,取决于参数的类型。
对于布尔类型的参数,我们有”+”或”-“,然后才设置JVM选项的实际名称。例如,-XX:+<name>
用于激活<name>
选项,而-XX:-<name>
用于注销选项。
对于需要非布尔值的参数,如string或者integer,我们先写参数的名称,后面加上”=”,最后赋值。例如, -XX:<name>=<value>
给<name>
赋值<value>
。
有两种类型的HotSpot JVM
注意
F:\Temp>java -versionjava version "1.8.0_92"Java(TM) SE Runtime Environment (build 1.8.0_92-b14)Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
显式虚拟机类型 当前版本号等等
这里注意JVM默认开启了mixmode混合模式,这意味着JVM在运行时可以动态的把字节码编译成本地代码F:\Temp>java -showversion Testjava version "1.8.0_92"Java(TM) SE Runtime Environment (build 1.8.0_92-b14)Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)hello world
1 ) -Xint 指令
int是interpretation的简称 翻译解释的意思 意味着强制JVM执行所有的字节码 这会降低运行速度[10倍左右]2 ) -Xcomp 指令
comp是Compile的简称 编译的意思 意味着JVM在第一次使用时会把所有的字节码编译成本地代码 从而带来最大程度的优化,虽然比-Xint的效率要高,但是它没有让JVM启动JIT编译器的全部功能, JIT编译器一般会在运行时创建方法使用文件 然后一步步的优化每个方法,因此该指令还是会造成一定的效率衰减3 ) -Xmixed 指令
JVM在运行时可以动态的把字节码编译成本地代码 默认开启了混合模式,因此无需显示的指定三种方式的对比 分别以以上三种指令运行程序
public static void main(String[] args) { /*run in -Xint 强制执行所有字节码 Average time: 3271*/ /*run in -Xcomp 第一次使用时把字节码转换成本地文件 Average time: 1874*/ /*run in -Xmixed JVM默认支持的模式 无需设置 Average time: 1250*/ long startTime = System.currentTimeMillis(); Mapmap = new HashMap<>(); for (int i = 0; i < 1000000; i++) { map.put(String.valueOf(i), i); } System.out.println("Average time: " + (System.currentTimeMillis() - startTime)); }
什么都不指定 默认混合模式的速度最快
Average time: 1326
-Xcomp 的效率略有衰减
Average time: 1913
-Xint 的效率最差
Average time: 3770
241 1 3 java.lang.String::equals (81 bytes) 243 2 3 java.lang.StringBuilder::append (8 bytes) 243 4 3 java.lang.Character::toLowerCase (9 bytes) 243 5 3 java.lang.CharacterData::of (120 bytes) 243 6 3 java.lang.CharacterDataLatin1::toLowerCase (39 bytes) 244 7 3 java.lang.CharacterDataLatin1::getProperties (11 bytes) 244 3 3 java.lang.AbstractStringBuilder::append (50 bytes) 244 11 n 0 java.lang.System::arraycopy (native) (static) ...
截取一小段分析
对于第一行241 1 3 java.lang.String::equals (81 bytes)
其中1就是顺序号表示唯一的编译任务,equals是编译的方法名 81bytes表示方法的大小 244 11 n 0 java.lang.System::arraycopy (native) (static)
这一行中编译的System::arraycopy表示编译的是System类的静态方法 arraycopy,且是本地方法因此前面有一个n参数
运行结果
Accumulated compiler times (for compiled methods only)------------------------------------------------ Total compilation time : 0.020 s Standard compilation : 0.020 s, Average : 0.000 On stack replacement : 0.000 s, Average : -1.#IO Detailed C1 Timings Setup time: 0.000 s ( 0.0%) Build IR: 0.006 s (37.6%) Optimize: 0.000 s ( 2.5%) RCE: 0.000 s ( 0.9%) Emit LIR: 0.006 s (40.7%) LIR Gen: 0.001 s ( 9.4%) Linear Scan: 0.005 s (30.7%) LIR Schedule: 0.000 s ( 0.0%) Code Emission: 0.002 s (13.6%) Code Installation: 0.001 s ( 8.0%) Instruction Nodes: 1800 nodes Total compiled methods : 50 methods Standard compilation : 50 methods On stack replacement : 0 methods Total compiled bytecodes : 2378 bytes Standard compilation : 2378 bytes On stack replacement : 0 bytes Average compilation speed: 121576 bytes/s nmethod code size : 34208 bytes nmethod total size : 59168 bytes
有些时候当设置一个特定的JVM参数时,JVM会在输出“Unrecognized VM option
”后终止。如果发生了这种情况,你应该首先检查你是否输错了参数。然而,如果参数输入是正确的,并且JVM并不识别,或许需要设置-XX:+UnlockExperimentalVMOptions 来解锁参数
[Global flags] uintx AdaptiveSizeDecrementScaleFactor = 4 {product} uintx AdaptiveSizeMajorGCDecayTimeScale = 10 {product} uintx AdaptiveSizePausePolicy = 0 {product} uintx AdaptiveSizePolicyCollectionCostMargin = 50 {product} uintx AdaptiveSizePolicyInitializingSteps = 20 {product} uintx AdaptiveSizePolicyOutputInterval = 0 {product} uintx AdaptiveSizePolicyWeight = 10 {product} uintx AdaptiveSizeThroughPutPolicy = 0 {product} uintx AdaptiveTimeWeight = 25 {product} bool AdjustConcurrency = false {product} bool AggressiveOpts = false {product} intx AliasLevel = 3 {C2 product} bool AlignVector = false {C2 product}...
第一列表示参数的数据类型 第二列是名称 第四列是值 第五列是参数的类别
第三列‘=’表示第四列是参数的默认值 “:=”表示参数被用户或者JVM赋值了例如使用-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal
指令运行后发现
uintx InitialHeapSize := 57505088 {product}uintx MaxHeapSize := 920649728 {product}uintx ParallelGCThreads := 4 {product}bool PrintFlagsFinal := true {product}bool UseParallelGC := true {product}
以上被赋值的参数
2 ) -XX:+PrintFlagsInitial
打印的是XX参数的初始化值3)-XX:+PrintCommandLineFlags
这个参数让JVM打印出那些已经被用户或者JVM设置过的详细的XX参数的名称和值。它列举出-XX:+PrintFlagsFinal
的结果中第三列有”:=”的参数。以这种方式,我们可以用-XX:+PrintCommandLineFlags作为快捷方式来查看修改过的参数-XX:InitialHeapSize=65596736 -XX:MaxHeapSize=1049547776 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
需要注意的是,所有JVM关于初始\最大堆内存大小的输出都是使用它们的完整名称:“InitialHeapSize”和“InitialHeapSize”。所以当你查询一个正在运行的JVM的堆内存大小时,如使用-XX:+PrintCommandLineFlags
参数或者通过JMX查询,应该寻找“InitialHeapSize”和“InitialHeapSize”标志而不是“Xms”和“Xmx”
-XX:+HeapDumpOnOutOfMemoryError
: 使得JVM在产生内存溢出时自动生成堆内存快照<path>
改变默认的堆内存快照生成路径,<path>
可以是相对或者绝对路径当内存发生溢出时 执行一串指令
$ java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:OnOutOfMemoryError ="sh ~/cleanup.sh" MyApp
$ java -XX:PermSize=128m -XX:MaxPermSize=256m MyApp
代码缓存内存区域 用来存储已编译方法生成的本地代码
如果代码缓存被占满,JVM会打印出一条警告消息,并切换到interpreted-only 模式:JIT编译器被停用,字节码将不再会被编译成机器码。因此,应用程序将继续运行,但运行速度会降低一个数量级如果代码缓存不断增长[因为热部署引起的内存泄露 提高代码的缓存大小只会延缓发生溢出]
根据的解决方法可以使用-XX:+UseCodeCacheFlushing使当代码缓存被填满时 让JVM放弃一些编译代码HotSpot中新生代被划分为3个区域
1.一个相对大点的区域—Eden区
2.两个相对小点的区域From Survivor和To Survior1.按照规定 新对象首先分配在Eden中[如果新对象过大 会直接分配在老生代中]
2.在GC中 Eden区的对象会被移动到Survivor中 直到对象满足一定的年纪[熬过GC的次数]会被移动到老生带GC过程
新生代的GC采用复制算法,在GC前To Survivor保持清空,对象保存在Eden和From Survivor中 GC运行时,Eden中的幸存对象被复制到To Survior中,针对From Survior中的幸存对象会考虑对象的年纪,如果年纪没有达到阈值,会被复制到To Survior去,如果达到阈值会被复制到老生代。
复制阶段完成后,Eden和From Survivor中只保存死对象,可以清空,如果在复制过程中To Survior被填满 剩余的对象会被复制到生代, 最后From Survivor和To Survior会调换名字总结:
设置新生代和老生代的相对大小
优点是新生代大小会随着整个堆大小动态扩展 -XX:NewRatio=3[老生代/新生代=3]指定Eden区和Survivor区的大小比例
注意两个幸存区是一样大的 -XX:SurvivorRatio=10 表示Eden区占整个新生代的10/12 每个Survivor占1/12指定JVM在每次新生代GC时 输出Survivor中对象的年龄分布
评价一个垃圾收集GC算法的两个标准
2.暂停时间越短算法越好
a) 吞吐量[throughput]:
JVM在专门的线程[GC Threads]中执行GC 只要GC线程是活动的 就会和应用程序线程[Application Threads]争用当前可用CPU的时钟周期 而吞吐量就是指应用程序线程占程序总用时的比例对于老生代提供了两种垃圾收集算法[除了新的G1的垃圾收集算法]
1.第一类尝试最大限度的提高吞吐量
2.第二类试图最小化暂停时间
老生代由于缺乏内存空间导致对象从年轻代移动到年老代失败时会触发垃圾收集器 ,从所谓的GC根开始,搜索堆中可到达对象并标记成活的 之后垃圾收集器把活的对象移动到年老代一块无碎片的内存块中 并标记剩余内存空间是空闲的。
垃圾收集器使用一个或多个线程来执行垃圾收集 使用多个线程时算法的不同步骤被分解 使得每个垃圾收集现在在自己的区域而不干扰其他线程
在垃圾收集期间 所有的应用程序线程暂停 只有垃圾收集完成之后才会重新开始激活串行垃圾收集器 例如单线程面向吞吐量的垃圾收集器 推荐用于只有单个CPU的JVM
使用多线程并行执行年轻代垃圾收集
除了激活年轻代并行垃圾收集,也激活了年老代并行垃圾收集
-XX:ParallelGCThreads=<value>
指定并行垃圾收集的线程数量
垃圾收集器能将堆大小动态变动像GC设置一样应用到不同的堆区域,只要有证据表明这些变动将能提高GC性能
-XX:GCTimeRatio=<value>
指定JVM吞吐量要达到的目标值
通过-XX:GCTimeRatio=<value>
告诉JVM最大暂停时间目标值[ms为单位]
并发标记清理收集器CMS收集器:低应用停顿时间
CMS收集器的过程可能存在的问题
解决方法:
激活CMS收集器 JVM默认使用的是并行处理器
使用CMS收集器时 激活年轻代使用多线程并行执行垃圾回收
注意: 最新的JVM版本,当使用-XX:+UseConcMarkSweepGC时,-XX:UseParNewGC会自动开启。 因此,如果年轻代的并行GC不想开启,可以通过设置-XX:-UseParNewGC来关掉。并发的CMS阶段以多线程执行 默认开启
-XX:ConcGCThreads=<value>
定义并发CMS中运行的线程数
-XX:CMSInitiatingOccupancyFraction=来设置,该值代表老年代堆空间的使用率。比如,value=75意味着第一次CMS垃圾收集会在老年代被占用75%时被触发。通常CMSInitiatingOccupancyFraction的默认值为68(之前很长时间的经历来决定的)。
命令JVM不基于运行时收集的数据来启动CMS垃圾收集周期
JVM通过CMSInitiatingOccupancyFraction的值进行每一次CMS收集,而不仅仅是第一次CMS默认不会对永久代进行垃圾回收 如果希望对永久代进行垃圾回收 可以设置此标志
注意,即使没有设置这个标志,一旦永久代耗尽空间也会尝试进行垃圾回收,但是收集不会是并行的,而再一次进行Full GC。开启CMS收集器的增量模式
ps:增量模式会经常暂停CMS过程 以便对应用程序作出完全的让步1.-XX:+ExplicitGCInvokesConcurrent
命令JVM无论什么时候调用系统GC,都执行CMS GC,而不是Full GC 2.-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses 保证当有系统GC调用时,永久代也被包括进CMS垃圾回收的范围内。因此,通过使用这些标志,我们可以防止出现意料之外的”stop-the-world”的系统GC。该标志将告诉JVM完全忽略系统的GC调用(不管使用的收集器是什么类型)
开启简单GC日志模式 为每一次新生代的GC和每一次Full GC打印一行信息
[GC 246656K->243120K(376320K), 0.0929090 secs][Full GC 243120K->241951K(629760K), 1.5589690 secs]
开始首先是GC类型 然后是在GC之前和之后使用的堆空间 然后是当前的堆容量 最后是GC的执行时间
开启了详细GC日志模式 此模式下的日志格式和GC算法有关
使用Throughput垃圾收集器在新生代中生成的日志[GC [PSYoungGen: 142816K->10752K(142848K)] 246648K->243136K(375296K), 0.0935090 secs][Times: user=0.55 sys=0.10, real=0.09 secs]
Full GC输出日志
[Full GC [PSYoungGen: 10752K->9707K(142848K)] [ParOldGen: 232384K->232244K(485888K)] 243136K->241951K(628736K) [PSPermGen: 3162K->3161K(21504K)], 1.5265450 secs]
缺省的GC日志时输出到终端的,使用-Xloggc:也可以输出到指定的文件。需要注意这个参数隐式的设置了参数-XX:+PrintGC和-XX:+PrintGCTimeStamps,但为了以防在新版本的JVM中有任何变化,我仍建议显示的设置这些参数。
转载地址:http://gqqli.baihongyu.com/