你假笨JVM参数 – 007 UseGCLogFileRotation NumberOfGCLogFiles GCLogFileSize

你假笨的第七次分享,也是你假笨在 2017 年的最后一次关于 JVM 的分享: 序号:007 时间:2017-08-10 参数: -XX:UseGCLogFileRotation -XX:NumberOfGCLogFiles -XX:GCLogFileSize 含义: 这次分享了3个设置滚动记录GC日志的参数 通过参数-Xloggc:xxx可指定GC日志文件路径 普通情况下,GC日志文件内容会不断积累,进程重启后日志文件会被覆盖 这次分享的3个参数在设置-Xloggc参数的前提下有效 -XX:UseGCLogFileRotation Enabled GC log rotation, requires -Xloggc. 打开或关闭GC日志滚动记录功能,要求必须设置 -Xloggc参数 -XX:NumberOfGCLogFiles Set the number of files to use when rotating logs, must be >= 1. The rotated log files will use the following naming scheme, .0, .1, …, .n-1. 设置滚动日志文件的个数,必须大于1 日志文件命名策略是,.0, .1, …, .n-1,其中n是该参数的值 -XX:GCLogFileSize The size of the log file at which point the log will be rotated, must be >= 8K. 设置滚动日志文件的大小,必须大于8k 当前写日志文件大小超过该参数值时,日志将写入下一个文件 ...

December 31, 2017 · 1 min · 92 words · Bridge Li

你假笨JVM参数 – 006 ExplicitGCInvokesConcurrent

你假笨的第六次分享: 序号:006 时间:2017-07-31 参数:-XX:ExplicitGCInvokesConcurrent 含义: Enables invoking of concurrent GC by using the System.gc() request. This option is disabled by default and can be enabled only together with the -XX:+UseConcMarkSweepGC option. System.gc()是正常FULL GC,会STW 打开此参数后,在做System.gc()时会做background模式CMS GC,即并行FULL GC,可提高FULL GC效率 注,该参数在允许systemGC且使用CMS GC时有效 举例: -XX:+ExplicitGCInvokesConcurrent 相关参数: -XX:DisableExplicitGC 控制是否允许System.gc(),默认允许 小程序截图: 分享记录:

December 23, 2017 · 1 min · 46 words · Bridge Li

你假笨JVM参数 – 005 CMSScavengeBeforeRemark

你假笨的第五次分享: 序号:005 时间:2017-07-24 参数:-XX:CMSScavengeBeforeRemark 含义: Enable scavenging attempts before the CMS remark step. 开启或关闭在CMS重新标记阶段之前的清除(YGC)尝试 CMS并发标记阶段与用户线程并发进行,此阶段会产生已经被标记了的对象又发生变化的情况,若打开此开关,可在一定程度上降低CMS重新标记阶段对上述“又发生变化”对象的扫描时间,当然,“清除尝试”也会消耗一些时间 注,开启此开关并不会保证在标记阶段前一定会进行清除操作 小程序截图: 分享记录:

December 17, 2017 · 1 min · 18 words · Bridge Li

你假笨JVM参数 – 004 MaxTenuringThreshold

你假笨的第四次分享: 序号:004 时间:2017-07-21 参数:-XX:MaxTenuringThreshold 含义: Sets the maximum tenuring threshold for use in adaptive GC sizing. The largest value is 15. The default value is 15 for the parallel (throughput) collector, and 6 for the CMS collector. 在可自动调整对象晋升老年代年龄阈值的GC中,该参数用于设置上述年龄阈值的最大值 参数值最大为15 Parallel Scavenge中默认值为15,CMS中默认值为6,G1中默认值为15 小程序截图: 分享记录:

December 10, 2017 · 1 min · 43 words · Bridge Li

你假笨JVM参数 – 003 CompileCommand

你假笨的第三次分享: 序号:003 时间:2017-07-19 参数:-XX:CompileCommand 含义: Specifies a command to perform on a method. 该参数用于定制编译需求,比如过滤某个方法不做JIT编译 若未指定方法描述符,则对全部同名方法执行命令操作,具体如何指定见下文[举例] 可使用星号通配符(*)指定类或方法,具体如何使用见下文[举例] 该参数可多次指定,或使用 换行符(\n)分隔参数后的多个命令 解析完该命令后,JIT编译器会读取.hotspot_compiler文件中的命令,该参数也可写在.hotspot_compiler文件中 可使用-XX:CompileCommandFile指定.hotspot_compiler文件为其他文件 用法: -XX:CompileCommand=command,method[,option] 命令: exclude,跳过编译指定的方法 compileonly,只编译指定的方法 inline/dontinline,设置是否内联指定方法 print,打印生成的汇编代码 break,JVM以debug模式运行时,在方法编译开始处设置断点 quiet,不打印在此命令之后、通过-XX:CompileCommand指定的编译选项 log,记录指定方法的编译日志,若未指定,则记录所有方法的编译日志 其他命令,option,help 举例: 设置编译器跳过编译com.jvmpocket.Dummy类test方法的4种写法 -XX:CompileCommand=exclude,com/jvmpocket/Dummy.test -XX:CompileCommand=exclude,com/jvmpocket/Dummy::test -XX:CompileCommand=exclude,com.jvmpocket.Dummy::test -XX:CompileCommand="exclude com/jvmpocket/Dummy test" 设置编译器只跳过编译java.lang.String类int indexOf(String)方法 -XX:CompileCommand=”exclude,java/lang/String.indexOf,(Ljava/lang/String;)I” 设置编译器跳过编译所有类的indexOf方法 -XX:CompileCommand=exclude,*.indexOf 小程序截图: 分享记录:

November 25, 2017 · 1 min · 46 words · Bridge Li

你假笨说JVM参数 – 002 StringTableSize

没想到距离第一次整理你假笨的分享已经过去两个多月了,近期会继续整理一系列你假笨关于JVM参数的分享,下面是第二次: 序号:002 时间:2017-07-14 参数:-XX:StringTableSize 含义:Number of buckets in the interned String table String.intern() 被调用时会往 Hashtable 插入一个 String(若该 String 不存在),这里的 Table 就是 StringTable,此参数就是这个 StringTable 的大小,若此参数设置过小,明显的问题就是过多的hash碰撞,造成在查找字符串时比较消耗 CPU 资源 JDK 1.6 起,当冲突次数超过 100 次会自动 rehash,即便如此,若此参数设置过小会导致不断的 rehash,依然会过度消耗 CPU 资源 建议将此参数设置的值稍大一些,以减少 hash 冲突 使用方法:-XX:ReservedCodeCacheSize=__ 小程序截图: 分享记录: 感谢你假笨

November 5, 2017 · 1 min · 42 words · Bridge Li

你假笨说JVM参数 – 001 ReservedCodeCacheSize

因为之前看过周志明《深入理解Java虚拟机JVM高级特性和最佳实践》,而对JVM的一些东西感兴趣,感觉挺好玩的,前段时间有幸加了阿里寒泉子的微信(现在应该是前阿里了),而加入了一个你假笨建的一个JVM参数交流群,你假笨在里面做过几次分享,看到有小伙伴整理笔记,表示赞同。因为俗话说好记性不如烂笔头,何况自己记性并不怎么好,以下是第一次的分享。另外虽然这些东西平时可能用不到,但当实际出问题的时候不懂这些肯定是束手无策,所以多看看总没有坏处 序号:001 时间:2017-07-13 参数:-XX:ReservedCodeCacheSize 含义:Reserved code cache size (in bytes) – maximum code cache size 用于设置Code Cache大小,JIT编译的代码都放在Code Cache中,若Code Cache空间不足则JIT无法继续编译,并且会去优化,比如编译执行改为解释执行,由此,性能会降低 等价参数:-Xmaxjitcodesize 使用方法:-XX:ReservedCodeCacheSize=__ 小程序截图: 分享记录: 文中小程序截图,是你假笨为了方便大家查询JVM参数而开发的一个小程序,大家可以搜索:JVMPocket添加到自己小程序中,没事的翻翻这些参数也挺好,另外JVMPocket里面有一个签到功能,你假笨会每天设置一个签到的目标人数,达到目标第二天就会在群里面分享一个JVM参数,所以大家可以每天签到,并加到你假笨建的的JVM参数交流群里面,当面听大神的教导。

August 26, 2017 · 1 min · 24 words · Bridge Li

Java GC之常见监控可视化工具总结(下)

上一篇文章总结一下监控和分析的常见命令,那些是基础,但是有些同学看到命令行就害怕,所以这篇文件总计一下两个常用的可视化工具。 JConsole JConsole工具在JDK/bin目录下,启动JConsole后,将自动搜索本机运行的jvm进程,不需要jps命令来查询指定。双击其中一个jvm进程即可开始监控,也可使用“远程进程”来连接远程服务器 进入JConsole主界面,有“概述”、“内存”、“线程”、“类”、“VM摘要”和”Mbean”六个页签: 内存页签相当于jstat命令,用于监视收集器管理的虚拟机内存(Java堆和永久代)变化趋势,还可在详细信息栏观察全部GC执行的时间及次数 线程页签:线程长时间停顿的主要原因有:等待外部资源(数据库连接、网络资源、设备资源等)、死循环、锁等待(活锁和死锁) 最后一个常用页签,VM页签,可清楚的了解显示指定的JVM参数及堆信息 VisualVM:多合一故障处理工具 VisualVM是一个集成多个JDK命令行工具的可视化工具。VisualVM基于NetBeans平台开发,它具备了插件扩展功能的特性,通过插件的扩展,可用于显示虚拟机进程及进程的配置和环境信息(jps,jinfo),监视应用程序的CPU、GC、堆、方法区及线程的信息(jstat、jstack)等。VisualVM在JDK/bin目录下 ①. 安装插件: 工具- 插件 ②. 监控垃圾回收 在左侧的“Application”测看下,有个“Local”节点,所有本地正在运行的Java应用都将罗列在这里。Java VisualVM是一个Java应用。所以,它将自己也列在这里。为了方便学习,我们将监控Java VisualVM自身的垃圾回收过程。双击“Local”节点下的VisualVM图标,现在,应用监视窗口在右侧打开。我们关注的是“Visual GC”,点击它 再配合其他的标签页,例如“Threads”以及线程转储你,我们就可以深入详细地了解这方面的内容。在“监视”标签页,我们可以监控整个堆内存的使用情况,这些都不贴图了,大家可以随便玩。 ③. 在VisualVM中生成dump文件 参考资料:周志明《深入理解Java虚拟机》第二版第四章

April 4, 2017 · 1 min · 23 words · Bridge Li

Java GC之常见垃圾收集器

上一篇文章简单写了JVM的常见垃圾回收算法,今天就让我们看看根据这些算法有哪些常见的垃圾收集器,他们有什么特点,然后根据自己的应用特点和要求组合出各个年代所使用的收集器。 上图展示了JDK1.7Update14之后的HotSpot虚拟机的7种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器 Serial收集器 Serial收集器是最基本、发展历史最悠久的收集器,在JDK 1.3.1之前是虚拟机新生代收集的唯一选择。见名知意它是一个单线程的收集器,“单线程”的意义并不仅仅说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束,也就是传说中的Stop The World,简称STW。那么它是不是已经被淘汰的一个垃圾收集器呢,事实上并不是,由于与其他收集器的单线程比简单而高效,对于限定单个CPU的环境来说,Serial收集器由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程收集效率。所以Serial收集器是虚拟机运行在Client模式下的默认新生代收集器。它的运行示意图如下: ParNew收集器 ParNew收集器其实就是Serial收集器的多线程版本,是一个并行垃圾收集器,并行的含义是:多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。除了使用多条线程进行垃圾收集之外,其余行为包括Serial收集器可用的所有控制参数、收集算法、Stop The World、对象分配规则、回收策略等都与Serial收集器完全一样,在实现上,这两种收集器也共用了相当多的代码。ParNew收集器是许多运行在Server模式下的虚拟机中首选的新生代收集器,还有一个和性能无关的但是很重要的原因:除了Serial收集器外,目前只有它能与CMS收集器配合工作。和Serial收集器相比,ParNew收集器在单CPU的环境中绝对不会有比Serial收集器更好的效果,甚至由于存在线程交互的开销,该收集器在通过超线程技术实现的两个CPU的环境中都不能百分之百地保证可以超越Serial收集器。然而,随着可以使用的CPU的数量的增加,它对于GC时系统资源的有效利用还是很有好处的。其运行示意图如下: Parallel Scavenge收集器 Parallel Scavenge收集器是一个新生代收集器,它也是使用复制算法的收集器,又是并行的多线程收集器。那么他有什么应用场景呢?事实上Parallel Scavenge收集器的特点是它的关注点与其他收集器不同,其他收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而Parallel Scavenge收集器的目标则是达到一个可控制的吞吐量(Throughput),所以由于与吞吐量关系密切,Parallel Scavenge收集器也经常称为“吞吐量优先”收集器。所以它的应用场景体现在:停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。除此之外和ParNew收集器相比,它具有自适应调节策略。Parallel Scavenge收集器有一个参数-XX:+UseAdaptiveSizePolicy。当这个参数打开之后,就不需要手工指定新生代的大小、Eden与Survivor区的比例、晋升老年代对象年龄等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics),其运行示意图如下: Serial Old收集器 Serial Old是Serial收集器的老年代版本,它同样是一个单线程收集器,使用标记-整理算法。它的主要应用场景:1. 给Client模式下的虚拟机使用(还记得Client模式下新生代的默认垃圾收集器是啥吗?);2. 在Server模式下,那么它主要还有两大用途:一种用途是在JDK 1.5以及之前的版本中与Parallel Scavenge收集器搭配使用,另一种用途就是作为CMS收集器的后备预案,在并发收集发生Concurrent Mode Failure时使用。运行示意图见Serial垃圾收集器 Parallel Old收集器 Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源敏感的场合,都可以优先考虑Parallel Scavenge加Parallel Old收集器。这个收集器是在JDK 1.6中才开始提供的,在此之前,新生代的Parallel Scavenge收集器一直处于比较尴尬的状态。原因是,如果新生代选择了Parallel Scavenge收集器,老年代除了Serial Old收集器外别无选择(Parallel Scavenge收集器无法与CMS收集器配合工作)。由于老年代Serial Old收集器在服务端应用性能上的“拖累”,使用了Parallel Scavenge收集器也未必能在整体应用上获得吞吐量最大化的效果,由于单线程的老年代收集中无法充分利用服务器多CPU的处理能力,在老年代很大而且硬件比较高级的环境中,这种组合的吞吐量甚至还不一定有ParNew加CMS的组合“给力”。直到Parallel Old收集器出现后,“吞吐量优先”收集器终于有了比较名副其实的应用组合。运行示意图见Parallel Scavenge垃圾收集器 CMS收集器 在JDK 1.5时期,HotSpot推出了一款在强交互应用中几乎可认为有划时代意义的垃圾收集器——CMS收集器,这款收集器是HotSpot虚拟机中第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程同时工作。并发的含义就是:指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另一个CPU上,他可不用同于并行,并行会有STW,并发几乎没有STW。CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。它的运行示意图如下: 从图上可以看出,CMS收集器是基于“标记—清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些,整个过程分为4个步骤: ①. 初始标记(CMS initial mark) 初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,需要“Stop The World”。 ...

February 26, 2017 · 1 min · 152 words · Bridge Li

Java GC之垃圾回收算法

上一篇文章简单写了一下JVM如何判断一个对象是否已经死了,当判断出一个对象已经死了之后,接下来就要进行垃圾回收了,所以在进行垃圾回收之前,先让我们看看垃圾回收的算法有哪些。 标记-清除算法 标记清除见名知意该算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成之后统一回收所有被标记的对象,至于如何标记就是上一篇文章中所讲的方法了。这种算法比较简单,容易理解,同时也是一个最基础的垃圾回收算法,后面所讲的算法都是对他的改进,至于为什么需要改进,因为他主要存在两个不足: ①. 效率问题,标记和清除两个阶段的效率都不高; ②. 空间问题,标记清除之后会留下大量的不连续的内存碎片,内存碎片会导致当后面在程序的运行过程中可能需要给较大的对象分配空间时,无法找到足够的内存而不得不提前触发另一次垃圾回收。这种算法的执行过程如下图: 复制算法 复制算法为了解决标记清除算法的效率问题:它将内存分为容量大小相同的两块,每次只使用其中一块,当这一块的内存空间用完了,他就讲里面存活着的对象复制到另一块上面,然后再把已使用过的这一块内存空间一次性清理掉,这样使得每次都是对半个内存区域进行会回收,内存分配时也不用考虑空间碎片的问题,只需要移动指针,按顺序分配即可,实现简单,运行高效。但是他也有缺点:每次使用的内存空间只有整个空间的一半,这“浪费”有点高啊。复制算法的执行过程如下图: 不过现代的商业JVM都采用了这种算法来回收新生代,究其原因不仅仅他解决了效率问题,更是经研究表明:新生代中的对象高达98%都是“朝生夕死”的,所以这样一来就不需要1:1来划分空间了。直接将内存空间分为一块较大的Eden区和两块较小的Survivor区,每次使用Eden和其中一块Survivor区,当需要回收时,直接将Eden和Survivor中还存活的对象一次性的复制到另一块Survivor区,最后在清理Eden和刚使用过的Survivor。HotSpot虚拟机Eden和Survivor的大小比例默认为8:1,也就是每次使用的空间大小是90%,只“浪费”了10%。但是98%的对象回收也不能保证,每次存活的对象所使用的空间小于10%,所以当Survivor空间不够时,就需要其他空间(一般是老年代)进行分配担保,如果另一块Survivor空间没有足够的空间存放上一次新生代垃圾回收存活的对象时,这些对象将直接通过分配担保机制进入老年代。 标记-整理算法 复制算法适用于新生代的对象“朝生夕死”,如果一个区域内的对象老是不死,不仅内次都需要复制大量的对象,效率很低,而且还需要额外的空间进行担保(分配担保是一个很复杂的东西,今后有机会会说到),所以对于老年代的对象,这种算法是不适合的,于是就提出了标记-整理算法。 标记-整理算法和标记-清除算法一样,也是分两个阶段,而且第一个阶段也一样,都是标记,所不同的是第二个阶段,不是对可回收的对象进行直接清理,而是让还存活着的对象向一端移动,然后直接清理掉端边界以为的内存空间,该算法的执行过程如下图: 分代收集算法 当前的商业JVM都是采用的这种算法,其实这种算法并没有什么新思想,而是根据对象存活周期的不同将内存划分几块,一般是把Java堆分为两块:新生代和老年代,这样就可以根据各个代的不同特点采取最适当的垃圾收集算法。新生代的对象大多都是“朝生夕死”的,而且还可以有老年代进行担保,那就采用复制算法,只需要付出少量的存活对象的复制成本就可以完成收集,而且一般也不需要启用担保策略,而老年代的对象存活率一般比较高、没有空间进行担保,就只有采用“标记-清理”或者“标记-整理”算法来进行回收了。 参考资料:周志明《深入理解Java虚拟机》第二版第三章

February 19, 2017 · 1 min · 16 words · Bridge Li