为什么 Java 要码农操心 JVM 性能调优?
为何 Java 码农在折腾 JVM 上乐此不彼?
这是什么癖好?
为何 Java 码农在折腾 JVM 上乐此不彼?
这是什么癖好?
你写了个很挫的代码, 不小心内存使用扩大了十倍
让你找下原因
这就是 jvm 的题目
所以 .net 没有这种问题是吗? 真的吗, 我不信.jpg
那么有一天, 你发现线上的 stw 时间翻了一倍, 让你找下原因
这就是调优
还是你说 .net 不会有这种问题
但没人会这么用. 操作系统也要占内存的啊.
你以为是在调什么, 写 JVM 的代码吗?
这是什么奇怪的东西?是 JVM 调优吗?
@FreeEx dot net 当然也需要,profiler 就是帮忙干这事的,但 dot net 不太会出现由于 CLR 参数设置不合理导致出问题,一般都是自己的问题或者 framework 中有 bug
这些在开发的时候基本上无需考虑,算是技术经理才需要想的问题吧。
作者:RednaxelaFX
链接: https://www.zhihu.com/question/52900051/answer/132583244
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
假定题主说的是下面三个层面的调优的头两种情况:
1.对 VM 的配置参数调优(例如 GC 参数)
2.对应用程序自身的代码调优
3.对 VM 自身的实现调优
(2)的话无论什么语言什么环境都好,追求性能的人肯定都有在做。Java 和.NET 都有好用的 profiler 可以帮助这方面的调查和调优。有时候参数调优还不够的地方,也只能自己改自己的应用代码来解决问题了。请看一个经典案例: https://samsaffron.com/archive/2011/10/28/in-managed-code-we-trust-our-recent-battles-with-the-net-garbage-collector
(3)的话,CLR 还没开源的时候,也无从调起。倒是有不少人给 Mono 贡献改进性能的 patch,也算是广义上“.NET”的 VM 实现层面调优吧。在 CoreCLR 开源后,也有不少人给 CoreCLR 贡献各种 patch 呢,包括“调优”。.NET 码农们以前时不时会中招的一种地方是程序进入 GC 的耗时( time-to-GC ),也就是从 CLR 说“我要开始做 GC 了”到“真正开始做 GC”之间的耗时。这里主要开销来自请求所有应用线程暂停( SuspendEE ),这些线程要多久才完成对该请求的响应。听说过这个过程中会发生“250ms 的倍数的等待时间”不?请跳传送门: http://blogs.microsoft.co.il/sasha/2009/07/31/garbage-collection-thread-suspension-delay-250ms-multiples/ 像这种问题就是不进到 VM 内部做修改的话无法解决的。
(1)的话,其实就算当年 CLR 还没开源的时候,CLR 也是有调优参数可以配置的呢。最经典的就是选择试用 Workstation GC ( WKS GC )或者 Server GC ( SVR GC )。见过<gcServer>参数不?后来可以配置使用 Concurrent GC 、Background Workstation GC 、Background Server GC 等。用户还可以在代码里通过 GCSettings.LatencyMode 属性来影响 GC 的行为。看,调优参数列表之一: https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/?redirectedfrom=MSDN
不过 CLR 跟 HotSpot VM 在配置上有一个显著的区别,就是 CLR 不需要用户指定一个“GC 堆的最大大小”。这跟 CLR 的 GC 堆的基础设计思路有关系。HotSpot VM 的 GC 堆一定要使用连续的虚拟地址空间。VM 在启动的时候会一口气 reserve GC 所需要的整个地址空间,然后再按需 commit 。-Xmx 会参与到 GC 堆最大大小的计算中。CLR 的 GC 堆则是分段式的( segemented ),GC 堆所用的空间会一个个 segment 分配,用满了一个再去分配一个新的; segment 不需要在连续的地址空间上。这样 GC 堆可以按需自动增长或者缩减,可以一直增长到耗尽虚拟地址空间或者达到配额。CLR 这种分段式 GC 堆的好处是,在 Windows 上,特别是 32 位 Windows 上,虚拟地址空间中用户程序可以用的部分是比较零碎的,想要用到尽就不能对“连续的地址空间”有太多要求,这种条件下 CLR 跑在 Windows 上就可以充分利用资源。而且这样一来,用户就不用头疼实现想好要配置多大的堆给 CLR 用了。反正它需要用多少会自己去增长。这用户体验就比绞尽脑汁想个好-Xmx 要爽。这种做法的坏处…怎能没有坏处呢。坏处也有若干。其中一个就是在这样的堆上实现的分代式 GC 的 write barrier 效率会比 HotSpot 那种用连续地址空间的要差一些。而且 segmented heap 实现起来也稍微复杂一些。
然而 JVM 做不到。我要让 JVM 不超过 1G 内存,那我得把 Xmx 设置为 512m,然后一小撮 VM 逼近 1G 内存,大部分 VM 跑 700M 。这些配置必须小心调教,不然有的服务就会疯狂 GC,干爆 CPU 。如果不小心把限制设的太宽,VM 们还会干爆内存,导致部分 VM 崩溃然后不停重新启动,于是服务器就挂了。
一般用到 jvm 调优的,大都是大数据,分布式的东西,非常吃内存的,经常有 GC 的。
通过调优,可能本来一台服务器 能跑 4 个实例的,内存就有些争用的,跑到 6 个了 或者原本 gc 到了 s 级的下降回 ms 级。
调优不是比烂,而是让好的更好。
深入到 GC 层去理解系统怎么执行的,是一个通过调优去理解 JVM,然后最终反馈到之后的代码编写方式的事情。
xmx 只是堆的大小
一台服务器跑几十个 vm 贼慢,已经不是能调优的了
如果 1 成立,2 是行为艺术么?
很讨厌这些面试 JVM 调优的题目,大部分也是网上剽切的内容,面试很多也拿出来装 B 而已。比如上面的 PermSize 之类,OpenJDK11 早就没用了。
@FreeEx 刚搜了一下,Java 9 支持从 cgroup 读取内存限制,Java 10 进一步优化了容器内存限制支持。然而我司是 Java 8
而同样部署到 win 一点问题没有,不知道是平台区别还是 win 买单了