转自:http://yoroto.io/nan-dao-ta-men-shuo-de-du-shi-zhen-de/

在我现在最推崇的那本关于Java性能的书籍Optimizing Java一上来,两位大大开篇就喷了已有的关于Java性能方面的书/文章/blog很多都是垃圾(你这篇blog也是喽)。主要的意思还是说,在这个领域,有太多的口口相传的过时的,甚至是完全拍脑门的性能传说经久不衰历久弥坚。虽然在贵Java界只混了几个月,我已经发现除了这本书可以信,R大说的都是对的,OpenJDK的源代码以外,呃,你还真没有什么敢轻易相信的。

谁知你匆匆的设置

事情的开始是这样的。在调查某个服务的GC性能问题的时候,除了修正主要问题(此处省去吹牛逼的512字),我发现以前的哥们设置了魔幻的ParGCCardsPerStrideChunk。打开这种JVM diagnostic选项,一般还是需要很大的勇气的。当时因为我知道他只是从另一个服务借过来的设置,所以在测试完关闭这个设置以后有小的GC性能提升之后,我就去处理主要的问题了。

(这一段是广告)这在以前,或者我相信在大多数企业,这就算完了。你解决了主要问题,挽救了社会挽救了党,谁还去管这种细节呢?然而在大亚麻,起码在我现在的部门,想到我们Senior Manager看到这个东西的时候那张写满了Leadership Principles的脸,我就知道只是做到这样的话,不算完。Dive Deep。

然后在北美的劳动节这天下午,我就来公司搞这个了。目的就是想知道,最初在另外一个服务搞了-XX:ParGCCardsPerStrideChunk=32768的根本原因是什么。

渐渐掩不住一丝尴尬

很快我就发现,网上有很多篇文章和blog,提到了这个设置。一般会说这会提高card table scan的效率,差一点的说这会提高worker thread的并行效率甚至搞不清是针对young gen还是old gen的,最可怕的是很多直接说你Heap大的时候直接用就好了。

反向继续搜索,就发现了大多数人是看了一篇LinkedIn的Engineering Blog。这篇讲到的很多地方还是非常有可取之处的,他们也是在测试了不同的配置之后得出了32768这个实验结论。但是后来的很多人以为这就是个神奇的值,也是够了。

而且他并不是一个人在战斗,一年之后Twitter的人还搞了一个OpenJDK的Ticket。他们发现对于他们来讲8192是个合适的值。这个我后面再讲。

不过LinkedIn做这件事的时候,也是基于一个俄国哥们Alexey Ragozin之前做的实验。他发现他的服务在4096时候达到最佳效果。这个著名的俄国人我还是很服的,就是他之前发现了card table scan的算法效率问题并且在7u40的时候patch了这个问题,并且发明了ParGCCardsPerStrideChunk这个参数。

写到这里大家起码都知道了,并不存在32768这个神奇的值。最早的人们是通过实验得出的对他们自己来说最合适的设置。后面直接拿这个数用的,呃,就有点东施效颦了。当然LinkedIn那篇blog写得也有问题,他没有交待清楚自己得到这个值的步骤,而且他能够说出“The interesting learning here was that the young GC time increases with the increase in the size of old generation”这句话,也说明他理解这件事有问题。

谁知你紧紧的计算

到这里当然还不算完啊,既然你们知道了这最后是找到一个平衡,那么是谁和谁之间的平衡呢?这就要讲到Generational Mark-Sweep算法的实现了。如果你们读过Garbage Collection或者The Garbage Collection Handbook,那就可以直接跳过这一章,哦,不对,你整个blog都不用读了。。。

如果你们没有读过,呃,我也帮你们找好了一篇MSDN的文章。读懂了,再接着往下看。虽然它讲的是.Net CLR的,但是已经是我能给你们找到的最合适的了,反正算法在这一层面差异不大。在教书育人这方面Java界确实长期以来很丢人。

在Java中,一个card的大小是512 bytes,而ParGCCardsPerStrideChunk默认的值是256。那么一个Stride,或者MSDN文章中说的block,就是512 * 256 = 128K。假如你有4G的old gen,就会有4G / 128K = 32K的Strides在young gen collection的时候去扫描。这也就是为什么我前面说LinkedIn文章的interesting有些大惊小怪,呃,算法本来就是这个样子的啊。随着old gen大小增加,young gen collection就是要做更多的事情。

在这个过程中,card table的scan,Stride向worker threads的分配,以及thread的Stride switching,都是有相当高的消耗。所以会存在如果Stride的大小太小,worker threads要做太多的调度和分配的话,会导致耗时增长。256这个当年最早时的默认值,在很多情况下,已经无法满足大的old gen的需求了。因此在很多场景下,增加到4K,8K,甚至32K会有显著的GC impact减小。然而这也不是必然的,比如你的代码、系统、负载决定了你根本没有什么old gen到young gen的reference的话,你就几乎没有什么dirty strides,这时即使你的old gen很大、负载非常大,消耗顶多是在card table scan上,256一样可能是一个非常适合的值。

而Stride size设置过大也是有问题的。因为在一个Stride里面,真的引用了young gen里面的对象的对象,可能只有一两个。如果Stride太大,worker thread就浪费了大量不必要的时间去试那些根本不存在这样的引用的对象上。这时候反而会更慢。

因此,你要找到的就是在上两段提到的这两种消耗上的一个平衡点。而根据各种JVM的设置和你的系统特性的不同,这个平衡点都是不一样的。甚至不同的运行环境中,比如不同的硬件,对于AWS来讲不同大小的region,可能都是不一样的。

再也藏不住心中扯淡

事情到这里还没有完。仍然有一些其他的JVM选项,可以影响这个过程。你们肯定马上想到了控制ParNew thread数量的ParallelGCThreads。更多的Thread,在有足够CPU core的帮助下(所以注意这句哦),确实可以更快得完成任务。而且你还可以设置ParGCStridesPerThread(注意这个也是个diagnostic的)控制每次worker thread整几个Strides,设置BindGCTaskThreadsToCPUs来减少thread的switching,设置UseGCTaskAffinity来保证每次worker thread被唤醒的时候争取拿到上次没有完成的工作。这里我就又要喷一句了,我还看到不少地方,有一些人说UseGCTaskAffinity没有用,因为那篇LinkedIn的blog里提到了这个参数对他们的系统好像没有什么用。于是到最后就传播成了,呃,“UseGCTaskAffinity没有用”。这个东西是干什么的,到底有用没有用,你真的找不到文章,去gcTaskManager.cpp里面看看get_task是怎么实现的,一分钟就明白了好不好!

还有一点就是前面提到的Twitter同学们搞的那个Ticket 。他们实验出来自己合适的设置后,然后在他们自己的OpenJDK分支上修改了,去通过设置old gen的大小,呃,在JVM启动时来决定到底应该把ParGCCardsPerStrideChunk设置成多大。仔细读了前面一章的都知道,这个并不是仅仅由old gen的大小决定的。更大的决定因素是你的系统。他们那么改可能适合了他们的一个服务,而不会是适合所有的场景。在我的实验中,不同的service达到的sweat point完全不一样。真的有很大old gen,256或者512是最佳设置的。根本的原因还是因为只是实验测试,没有去理解算法啊。。。况且他建议给出一个范围在运行时调整。呃,他有想过如果运行时调整这个,那意味着card table的大小要变,card table的值要重新build;如果合并还好办,但是如果分成更多的区域,那么要整个区域重新扫描的。。。

说什么痴情的脚步追不上变心的翅膀

好了,这个故事讲完了。最后总结一下的话,可以列为三点:

  • R大说的都是对的。
  • R大说的都是对的。
  • R大说的都是对的。

这你们早都知道?好吧,重新来过:

  • R大说的都是对的,Optimizing Java是可以读的,JVM源代码是真理所在。
  • 除了上面的之外,网上所有的关于JVM性能的文章,都要打破沙锅问到底,尤其是作者没有问到底的。因为有太多JVM界的Steve Bannon。(那你是JVM界的Bernie Sanders喽(好像也好不到哪里去啊?
  • 实验和测试只是一方面,更重要的是理解算法,这样才能真正理解和解决问题。

转载于:https://www.cnblogs.com/leonxyzh/p/7484212.html

难道他们说的都是真的?相关推荐

  1. 38岁了,难道程序员35岁以后真的都要失业了吗?

    ‍ ‍刚打开头条,收到平台推送的一条邀请问道: 38岁了,难道程序员35岁以后真的都要失业了吗? 之前也回答过类似这样的问题,感觉之前的回答有些过于笼统,没有真正贴近实际案例. 以前我也时常在思考一个 ...

  2. C语言小学生都能学会,你还说单片机很难,难道你连小学生都不如吗

    C语言小学生都能学会,你还说单片机很难,难道你连小学生都不如吗 我是很认真的,没有在跟你吹水,前段时间有邻居知道我是攻城狮,闲聊的时候想让我带他的女儿学习单片机,当时我就拒绝了,因为在我的认知范围里这 ...

  3. 人心隔肚皮,如何才能保证别人对你说的都是真的?

    职场上,有时候我们根本不知道身边的同事对你到底是真心还是虚情假意,或许大家是利益的共同体,利益相同的时候是朋友,利益冲突是敌人. 同事之间并不一定不能真心交朋友,如果遇到志同道合的,也是可以敞开心扉的 ...

  4. 所有男孩子在发誓的时候都是真的觉得自己一定不会违背承诺

    所有男孩子在发誓的时候都是真的觉得自己一定不会违背承诺,而在反悔的时候也都是真的觉得自己不能做到,所以誓言这种东西无法衡量坚贞,也不能判断对错,它只能证明,在说出来的那一刻,彼此曾经真诚过.

  5. 要闻君说:难道金山云与京东云真的要合并了吗?中国联通获准发行不超过500亿元公司债券,都用于5G 商用?用AI技术精准来找室友?...

    关注并标星星CSDN云计算 每周三次,打卡即read 更快.更全了解泛云圈精彩news go go go  嗨,大家好!偶是要闻君.愉快的周一从"听歌+看新闻"开始啦! 文/要闻君 ...

  6. 某程序员以阿里为原型写小说!阿里员工:每件事都是真的!网友:建议拍成电视剧!...

    程序员群体里真是卧虎藏龙,除了写代码,他们还有很多隐藏大招,比如唱歌,画画,写小说-- 一个程序员就在网上贴出了自己的短篇小说<我为什么辞职>,其文笔之流畅,立意之深远,暗喻之精妙让人拍案 ...

  7. 有趣的历史,据说都是真的

    原文: http://blog.csdn.net/masterall/archive/2006/09/07/1191711.aspx

  8. 关键系统的JVM参数推荐

    前言2, -XX:+PrintFlagsFinal打印参数值 当你在网上兴冲冲找到一个可优化的参数时,先打印看看,它可能已经默认打开了,再找到一个,还是默认打开了... JDK7与JDK8,甚至JDK ...

  9. 巴士拉银匠哈桑的故事(二)

    "是这样的,姐姐们,我们奉命回去参加婚礼的那段时间,他一个人留在宫中,感到十分孤单寂寞,又担心又有人闯进宫来对他不利.姐姐们都知道,人类是很浮躁的,遇事不多加思索,因此,当他百无聊赖的时候, ...

最新文章

  1. 李彦宏,韩寒等入围本年度《时代百人》候选名单
  2. JVM 从入门到“精通”,妥妥的
  3. 技能树升级——Chrome Headless模式 - 全栈客栈 - SegmentFault
  4. ArcGIS API for JavaScript4.x 之加载2D、3D地图
  5. 500元辛苦费,求一C#算法,自由定义表达式
  6. goland os.Open 路径错误
  7. 整数点与Pick定理
  8. SpringMVC的数据响应-回写数据-直接回写字符串(应用)
  9. TOPSIS与模糊Borda 的组合应用(以第二届大湾区杯和国赛为案例)
  10. Oracle 11g 频繁遭遇 CheckPoint incomplete问题分析(直播预告)
  11. (Mirage系列之四)Mirage经典案例之集中桌面管理
  12. 实用的 Python 之 feedparser
  13. 双目视觉图像的色彩调整
  14. 【安装教程】 【Visio2019】(附带安装包下载)
  15. 基于FPGA打地鼠游戏的设计与实现
  16. idea翻译插件Translation Tkk错误
  17. 第十五届北京师范大学程序设计竞赛 [(6+1)/11,待补]
  18. 全新Thinkphp养我吧宠物区块链网站源码+可封装APP源码 免费下载 源码搭建教程
  19. 强平日志模块-埋点方案
  20. 用EasySysprep封装Win7系统,做自己的操作系统,适用win8,win10-一键安装win7

热门文章

  1. 在word、excel中如果运用VBA进行编程?
  2. 视频检测分割--Deep Feature Flow for Video Recognition
  3. Python 基础 二
  4. Python-anaconda-Spyder使用matplotlib画图无法显示报错解决:Figures now render in the Plots pane by default. To mak
  5. 我看过的编译原理方面的好文章
  6. oracle迁移mysql视图中函数问题,mysql中to_char自定义函数。
  7. css 不展示滚动条,CSS-界面滚动时不显示滚动条
  8. java 字符串xml,解析java中的xml字符串?
  9. mini mysql_mini
  10. mysql时间戳group by操作,mysql使用FROM_UNIXTIME将时间戳按日期group by