难道他们说的都是真的?

转自: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喽(好像也好不到哪里去啊?
  • 实验和测试只是一方面,更重要的是理解算法,这样才能真正理解和解决问题。
时间: 2024-08-03 22:25:47

难道他们说的都是真的?的相关文章

百度如果不做医疗行业的推广,你搜索到的就都是真的了?

2016年4月12日,魏则西父亲代他在知乎留言,「我是魏则西的父亲魏海全,则西今天早上八点十七分去世,我和他妈妈谢谢广大知友对则西的关爱,希望大家关爱生命,热爱生活.」 当时他应该不会想到,半个月后,舆论掀起,全国几乎所有的网民都走到百度的对立面. 魏则西在之前是通过百度搜索到「武警北京总队第二医院」,因为信息不实导致了他错过了最佳治疗时间.以下是他在知乎上的文章节选: 有此可见,「百度」确实成为事件的导火索.不可否认地成为了魏则西病逝的直接原因之一,在道德与利益的交叉口,百度的天平明显偏颇,导

专访TK教主于旸:原来那些搞安全的说的都是真的(图灵访谈)

引用:http://www.ituring.com.cn/article/196609 于旸,网名“tombkeeper”,在国内黑客界被尊称为“TK教主”,现任腾讯玄武实验室总监.于旸从事信息安全研究工作十余年,主要研究方向聚焦在针对各类型漏洞的挖掘.利用.检测.防御,以及涉及硬件.无线等方面的复合安全风险.他曾发现并报告了Cisco.Microsoft等公司产品的多个安全漏洞.在2008年北京奥运期间,他曾担任公安部奥运会信息网络安全指挥部技术专家,及CNCERT奥运信息安全保障小组技术专家

关键业务系统的JVM参数推荐(2018仲夏版) (强烈推荐 唯品会)

年更贴,因为两年里遇到的事情,一些想法变了.也补充了不少VJTools的内容,比如为伸手党们准备的jvm-options.sh. 在关键的业务系统里,除了继续追求技术人员最爱的高吞吐与低延时之外,系统的稳定性与排查问题的便捷性也很重要.这是本文的一个原则,后面也会一次又一次的强调. 前言1,资料 1. 学习开源项目的启动脚本是个不错的主意,比如ElasticSearch家的,Cassandra家的, 附送一篇解释它的文章. 2. VJTools的 jvm-options.sh,伸手党们最爱,根据

关键系统的JVM参数推荐

1. 性能篇 1.1 建议的性能参数 1. 取消偏向锁: -XX:-UseBiasedLocking JDK1.6开始默认打开的偏向锁,会尝试把锁赋给第一个访问它的线程,取消同步块上的synchronized原语.如果始终只有一条线程在访问它,就成功略过同步操作以获得性能提升. 但一旦有第二条线程访问这把锁,JVM就要撤销偏向锁恢复之前的状态,如果打开安全点日志,可以看到不少RevokeBiasd的纪录,像GC一样Stop The World的干活,虽然只是很短的停顿,但对于多线程并发的应用,取

你真的认为iphone只是一部手机么

闲言不表,直奔主题.我是一个程序员,上周参加了一个开源软件交流大会,其实会上并没有听到什么新鲜的东西.但是在会中,偶然间听到了一个关于iphone的秘密,却着实令我震惊了,事情具体是这样的,听我慢慢道来. 大会是上午9:00点开始,主持人寒暄了一会,就由国内国外的一些it行业的从业人员来分享自己在开发中的一些经验,心得等等!由于我是被领导派来参加的,所以,本来也没什么兴趣,于是就在下面悄悄的玩起了手机. 我旁边坐的是一位文质彬彬的台湾人,个子不高,带着眼镜,书生气很浓,大概40岁上下,他也没怎么

每一个程序员都应当了解的11句话

每一个程序员都应当了解的11句话,你最同意哪一句? 1. 技术只是解决问题的选择,而不是解决问题的根本 我们可以因为掌握了最新的 JavaScript 框架 ahem.Angular 的 IoC 容器技术或者某些编程语言甚至操作系统而欢欣雀跃,但是这些东西并不是作为程序员的我们用来解决问题的根本——它们只是用于帮助我们解决问题的简单工具. 我们必须非常谨慎,不要对某项正好喜欢或者正好很火的特定技术走火入魔.否则,我们将进入这样的思维怪圈:把掌握的那项技术比做是锤子,在思考问题时,会自然的把所有的

【转】移动互联网测试面试之我的要求真的不高

好吧,我已经忍了很久了.我在行业中什么脾气大家很多人也知道了,所以我是忍不住的.今天借着林应的一条微博我也爆发以下吧.如果不了解我风格的可以搜索“陈晔 测试”或者购买<大话移动app测试——Android与iOS应用测试指南>(清华大学出版社)清洗三观之后再做测试,嗯. 支付宝也不是一家小公司了,首先我是上海无线业务团队负责测试技术,现在很缺人,大家有兴趣的也可以投简历.我认为我很尊重每个来面试的同学,只要来过的同学我都会耐心和他不足,但是也请你们尊重以下我好么?我真的要求很高么?大家请看我下

每个程序员都应该了解的十一句话

 文来自泡面吧 侵删 1.技术只是解决问题的选择,而不是解决问题的根本 我们可以因为掌握了最新的JavaScript框架ahem.Angular的IoC容器技术或者某些编程语言甚至操作系统而欢欣雀跃,但是这些东西并不是作为程序员的我们用来解决问题的根本--它们只是用于帮助我们解决问题的简单工具. 我们必须非常谨慎,不要对某项正好喜欢或者正好很火的特定技术走火入魔.否则,我们将进入这样的思维怪圈:把掌握的那项技术比做是锤子,在思考问题时,会自然的把所有的问题都想象成是锤子可以解决的钉子. 2.聪明

专家是什么?我真的想知道(转)

英文原文:What’s An Expert? I Sincerely Want To Know. 有人在 Quora 问道,”答案应该被分类为专家级/非专家级吗?“ 我回应: 没有专家这回事儿. 首先,有一堆轶事. 在 1799 年,乔治·华盛顿感冒了,他咳嗽.发高烧.这被视作紧急情况,最伟大的.在世的美国人生病了!在此之前的大约 2000 年里,血液被认为是身体里的主要力量.如果某人病了,血液中的某些东东需要被排出去.最终,放血.我不知道吸血的水蛭是否参与了.第二天乔治·华盛顿去世了.死因不是