因为题主您就是没听说过 >_<||||
假定题主说的是下面三个层面的调优的头两种情况:
(2)的话无论什么语言什么环境都好,追求性能的人肯定都有在做。Java和.NET都有好用的profiler可以帮助这方面的调查和调优。
有时候参数调优还不够的地方,也只能自己改自己的应用代码来解决问题了。请看一个经典案例:
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的倍数的等待时间”不?请跳传送门:
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的行为。
看,调优参数列表之一:
Runtime Settings Schema不过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实现起来也稍微复杂一些。