大家好,我已将java.util包中的ArrayList源代码复制到我自己的包中。但是我发现它比原始的java.util.ArrayList运行得更好。
测试代码:
@Test
public void jdkApiPerformance() {
long startTime = System.nanoTime();
java.util.ArrayList<Object> list = new java.util.ArrayList<Object>();
long costTime = System.nanoTime() - startTime;
System.out.println("jdkPerformance cost " + costTime + "ns.");
}
@Test
public void myApiPerformance() {
long startTime = System.nanoTime();
question.jdk.ArrayList<Object> list = new question.jdk.ArrayList<Object>();
long costTime = System.nanoTime() - startTime;
System.out.println("apiPerformance cost " + costTime + "ns.");
}
此测试的输出为打击:
jdkPerformance cost 10263ns. apiPerformance cost 1244158ns.
显然,我的api运行速度比JDK api慢。
然后我为此测试添加了@Before方法:
@Before
public void setUp() {
new java.util.ArrayList<Object>();
new question.jdk.ArrayList<Object>();
}
此案例的输出已更改:
jdkPerformance cost 9932ns. apiPerformance cost 1324ns.
我的api跑得比JDK api快!!
我对这种情况感到很困惑。请帮助我。谢谢。
答案 0 :(得分:2)
1)使用System.nanoTime()
可能会给您带来扭曲的结果,因为它取决于操作系统的调度程序粒度:
此方法提供纳秒级精度,但不一定是纳秒级分辨率(即值的变化频率) - 除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。
2)要有有意义的基准,你必须先预热 JVM
3)对于研究,你可以使用一个基准测试库:
4)一般来说,你的问题的答案是:是,在某些情况下,Sun / Oracle的JVM热替换一些JDK代码,例如Math.sqrt()
,并针对给定的OS优化了实现硬件
答案 1 :(得分:1)
JVM按需加载类。由于java.util.ArrayList是这样一个基础类,它可能已经在您的基准测试开始之前加载,但是question.jdkArrayList可能是第一次使用。这涉及读取类文件的磁盘I / O,这本身比创建新实例花费的时间要多几个数量级。此外,Java.util.ArrayList更有可能由JIT编译器进行优化。
根据其javadoc,System.nanoTime()具有“纳秒级精度,但不一定是纳秒精度”。用它来测量微秒级的延迟就是充其量。此外,它还可以测量挂钟时间,而不是CPU时间。如果您的cpu被占用(例如,在开发环境中绘制控制台视图),将计入报告的时间。