【发布时间】:2013-03-04 13:43:04
【问题描述】:
考虑以下两个代码示例。所有基准测试都是在用于计算采样执行时间平均值的容器之外完成的。在我的机器上,运行 Windows 7 和 JDK 1.6,我看到示例 2 中的平均执行时间比示例 1 慢了近 1,000 倍。我可以推测的唯一解释是编译器正在优化 LinkedList 使用的一些代码以其他一切的损害。有人可以帮我理解这一点吗?
示例 1:使用数组
public class TimingTest
{
static long startNanos, endNanos;
static long[] samples = new long[1000];
public static void main(String[] args)
{
for (int a = 0; a < 100; a++)
{
for (int numRuns = 0; numRuns < 1000; numRuns++)
{
startNanos = System.nanoTime();
long sum = 0;
for (long i = 1; i <= 500000; i++)
{
sum += i % 13;
}
endNanos = System.nanoTime() - startNanos;
samples[numRuns] =(endNanos);
}
long avgPrim = 0L;
for (long sample : samples)
{
avgPrim += sample;
}
System.out.println("Avg: " + (avgPrim / samples.length) );
}
}
}
示例 2:使用 LinkedList
public class TimingTest
{
static long startNanos, endNanos;
static List<Long> samples = new LinkedList<Long>();
public static void main(String[] args)
{
for (int a = 0; a < 100; a++)
{
for (int numRuns = 0; numRuns < 1000; numRuns++)
{
startNanos = System.nanoTime();
long sum = 0;
int index = 0;
for (long i = 1; i <= 500000; i++)
{
sum += i % 13;
}
endNanos = System.nanoTime() - startNanos;
samples.add(endNanos);
}
long avgPrim = 0L;
for (long sample : samples)
{
avgPrim += sample;
}
System.out.println("Avg: " + (avgPrim / samples.size()));
}
}
}
【问题讨论】:
-
链表的性能特征比数组差,没什么大不了的。
-
未对 LinkedList 进行基准测试! LinkedList 仅存储基准测试结果。
-
@vemv 这是一个不完整且具有误导性的分析。链表具有比数组更好的性能特征。另外,在第二个例子中,求和代码的执行时间比较慢。
-
我的赌注。将元素添加到列表的操作比添加到数组所需的操作要长;因此,当您返回循环代码时,您更有可能遭受 缓存未命中。尝试在每个循环之后放置一些复杂的操作(一些
System.out.println,创建一些新对象),您会发现两个代码的性能都会收敛。 -
你的内部循环基本上什么都不做。它可以被完全删除。通常的自适应编译器行为意味着这不会立即发生。基准代码的方法很长,因此可能会影响行为。我建议首先将两次调用
nanoTime之间的代码移动到不同的方法中。 (LinkedList通常性能很差,即使人们认为它会运行得很快。)
标签: java arrays performance collections jit