我已经在 Eclipse 中为 Java Web 服务项目创建了客户端和服务器。我试图做的是 -
第 1 步 - 进行 1000 次服务器调用并测量每次调用的平均时间。
第 2 步 - 进行 100000 次服务器调用并测量每次调用的平均时间。
我看到的是,第 2 步中每个呼叫的平均时间少于第 1 步中的平均时间。有人可以指导我为什么会这样吗?
谢谢,普拉特
我已经在 Eclipse 中为 Java Web 服务项目创建了客户端和服务器。我试图做的是 -
第 1 步 - 进行 1000 次服务器调用并测量每次调用的平均时间。
第 2 步 - 进行 100000 次服务器调用并测量每次调用的平均时间。
我看到的是,第 2 步中每个呼叫的平均时间少于第 1 步中的平均时间。有人可以指导我为什么会这样吗?
谢谢,普拉特
从进行数百次负载测试的经验来看,我认为这可能是因为预热时间。你有考虑过这个吗?通常系统需要更多时间来处理前 N 个调用。这可能是因为...
- thread pools need to be initialized
- database connection pools must be populated
- classes may need to be populated into permgen for the first time
- | insert another init action here |
经过几次迭代后,预热时间趋于均匀,因此数字越大,平均值越好。经过数千次迭代,“预热时间”不再重要。您可以通过在前 X 秒内进行几次调用并给服务器时间预热来解决小迭代问题。预热后增加用户/线程数。例如,Jmeter 有办法做到这一点。
我猜JIT是原因。
几乎所有的JVM都会在你运行程序的时候做JIT,但是它有自己的条件来启动JIT。鉴于您使用的 JDK 是 Oracle JDK。你可以选择两种模式来运行你的JVM,客户端和服务器,两种模式下启动JIT的条件是不同的。我猜你选择的模式是服务器。
依赖于两个计数器,Invocation Counter 和 Back Edge Counter,JIT 会将你的 java 字节码编译为本机代码,这可以提高你的应用程序性能。
Invocation Counter会统计方法的调用次数。当它大于某个值时,JIT 开始将“热”方法编译为本机代码并替换旧代码。下次调用该方法时,程序将运行本机代码。
后沿计数器将计算循环中的时间。当它大于某个值时,JIT 会将该循环中的代码编译为本机代码并替换旧代码。因为替换在调用堆栈上,所以也称为OSR(On Stack Replacement)。
您可以通过 JVM 参数 -XX:CompileThreshold=10000 来控制 Invocation Counter 的“某个值”。即调用 10000 次后,该方法将被编译,而 10000 是服务器模式下的默认值。
您可以通过 JVM 参数 -XX: OnStackReplacePercentage=140 来控制 Back Edge Counter 的“某个值”。这里有一个公式。“某个值”=(CompileThreshold * (OnStackReplacePercentage - InterpreterProfilePercentage))/100。默认情况下,服务器模式下 InterpreterProfilePercentage=33 和 OnStackReplacePercentage=140。Thar 是,如果循环中的运行时间超过 10700,JIT 将启动。
总的来说,我认为第2步的调用时间会触发JIT,所以第2步的性能更高。