我正在对 MPEG 解码器进行一些优化。为了确保我的优化不会破坏任何东西,我有一个测试套件可以对整个代码库(优化的和原始的)进行基准测试,并验证它们是否产生相同的结果(基本上只是通过解码器和 crc32 提供几个不同的流输出)。
在 Sun 1.6.0_18 中使用“-server”选项时,测试套件在预热后的优化版本上运行大约慢 12%(与默认的“-client”设置相比),而原始代码库获得了良好的提升运行速度大约是客户端模式下的两倍。
虽然起初这对我来说似乎只是一个热身问题,但我添加了一个循环来多次重复整个测试套件。然后从测试的第 3 次迭代开始,每次通过的执行时间变得恒定,但优化后的版本仍然比客户端模式慢 12%。
我也很确定这不是垃圾收集问题,因为代码在启动后绝对不涉及对象分配。该代码主要由一些位操作操作(流解码)和许多基本的浮动数学(生成 PCM 音频)组成。唯一涉及的 JDK 类是 ByteArrayInputStream(将流提供给测试并从测试中排除磁盘 IO)和 CRC32(用于验证结果)。我还观察到 Sun JDK 1.7.0_b98 的相同行为(只有 15% 而不是那里的 12%)。哦,测试都是在同一台机器(单核)上完成的,没有运行其他应用程序(WinXP)。虽然测量的执行时间存在一些不可避免的变化(使用 System.nanoTime btw),但使用相同设置的不同测试运行之间的变化从未超过 2%,通常小于 1%(预热后),
是否有任何已知的编码模式在服务器 JIT 上表现更差?如果做不到这一点,哪些选项可用于“窥视”引擎盖并观察 JIT 在那里做什么?
也许我用错了我的“热身”描述。没有明确的预热代码。整个测试套件(由 12 个不同的 mpeg 流组成,总共包含约 180K 音频帧)执行 10 次,我将前 3 次运行视为“热身”。在我的机器上,一轮测试大约需要 40 秒 100% cpu。
我按照建议使用 JVM 选项并使用“-Xms512m -Xmx512m -Xss128k -server -XX:CompileThreshold=1 -XX:+PrintCompilation -XX:+AggressiveOpts -XX:+PrintGC”我可以验证所有编译都发生在前3轮。垃圾收集每 3-4 轮启动一次,最多耗时 40ms(512m 非常大,因为测试可以用 16m 运行就好了)。由此我得出结论,垃圾收集在这里没有影响。尽管如此,将客户端与服务器进行比较(其他选项不变)仍然存在 12/15% 的差异。