Java理论与实践: 动态编译与性能测量 - 编程入门网
客户机和服务器 JVM 中 StupidThreadBenchmark 的性能
对于评测静态编译语言来说,处理过于积极的死代码清除也是一个问题。但 是,在静态编译语言中,能够更容易地发现编译器清除了大块评测。您可以查看 生成的机器码,查看是否漏了某块程序。而对于动态编译语言,这些信息不太容 易访问得到。 预热 如果您想测量 X 的性能,一般情况下您是想测量它编译后的性能,而不是它 的解释性能(您想知道 X 在赛场上能跑多快)。要做到这样,需要“预热” JVM —— 即让目标操作执行足够的时间,这样编译器在为执行计时之前,就有 足够的运行解释的代码,并用编译的代码替换解释代码。 使用早期 JIT 和没有栈上替换的动态编译器,有一个容易的公式可以测量方 法编译后的性能:运行多次调用,启动计时器,然后执行若干次方法。如果预热 调用超过方法被编译的阈值,那么实际计时的调用就有可能全部是编译代码执行 的时间,所有的编译开支应当在开始计时之前发生。 而使用今天的动态编译器,事情更困难。编译器运行的次数很难预测,JVM 按照自己的想法从解释代码切换到编译代码,而且在运行期间,相同的代码路径 可能编译、重新编译不止一次。如果您不处理这些事件的计时问题,那么它们会 严重歪曲您的计时结果。 图 1 显示了由于预计不到的动态编译而造成的可能的计时歪曲。假设您正在 通过循环计时 200,000 次迭代,编译代码比解释代码快 10 倍。如果编译只在 200,000 次迭代时才发生,那么您测量的只是解释代码的性能(时间线(a))。如果编译在 100,000 次迭代时发生,那么您总共的运行时间是运行 200,000 次 解释迭代的时间,加上编译时间(编译时间非您所愿),加上执行 100,000 次 编译迭代的时间(时间线(b))。如果编译在 20,000 次迭代时发生,那么总时 间会是 20,000 次解释迭代,加上编译时间,再加上 180,000 次编译迭代(时 间线(c))。因为您不知道编译器什么时候执行,也不知道要执行多长时间,所 以您可以看到,您的测量可能受到严重的歪曲。根据编译时间和编译代码比解释 代码快的程度,即使对迭代数量只做很小的变化,也可能造成测量的“性能”有 极大差异。 图 1. 因为动态编译计时造成的性能测量歪曲 那么,到底多少预热才足够呢?您不知道。您能做到的最好的,就是用 - XX:+PrintCompilation 开关来运行评测,观察什么造成编译器工作,然后改变 评测程序的结构,以确保编译在您启动计时之前发生,在计时循环过程中不会再 发生编译。 Java理论与实践: 动态编译与性能测量(4)时间:2010-12-21 IBM Brian Goetz不要忘记垃圾收集 那么,您已经看到,如果您想得到正确的计时结果,就必须要让被测代码比 您想像的多运行几次,以便让 JVM 预热。另一方面,如果测试代码要进行对象 分配工作(差不多所有的代码都要这样),那么垃圾收集器也肯定会运行。这是 会严重歪曲计时结果的另一个因素 —— 即使对迭代数量只做很小的变化,也意 味着没有垃圾收集和有垃圾收集之间的区别,就会偏离“每迭代时间”的测量。 如果用 -verbose:gc 开关运行评测,您可以看到在垃圾收集上耗费了多少时 间,并相应地调整您的计时数据。更好一些的话,您可以长时间运 |
|||||||||||||||
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |