基准小型阵列与列出了在Java:是我的基准代码错误的吗?
-
19-09-2019 - |
题
免责声明: 我已经看过 此 的问题 和 这个问题 但他们都得脱轨,通过小 详细信息和通 优化的,是不必要的问题。我真正需要的所有性能我 可以得到我的当前应用程序,这是 接收处理喷涌的MIDI数据 在实时。还需要扩大规模 以及可能的。
我比较 array
性能上的大量读于小型列出来 ArrayList
并且还只是具有的变量。我发现这一系列节拍 ArrayList
2.5个系数和 甚至是跳只是具有象引用。
我想知道的是:
- 是我的基准,好吗? 我已经换了测试和运行次数没有变化.我还用毫秒,而不是纳秒都无济于事。
- 我应该指定任何Java选项,尽量减少这种差异?
- 如果这种差异是真实的,在这种情况下 我不喜欢
Test[]
要ArrayList<Test>
在这种情况下,把在码需要将他们吗? 显然我读很多书写。
JVM Java1.6.0_17在OS x和它肯定是在运行中的热点模式。
public class ArraysVsLists {
static int RUNS = 100000;
public static void main(String[] args) {
long t1;
long t2;
Test test1 = new Test();
test1.thing = (int)Math.round(100*Math.random());
Test test2 = new Test();
test2.thing = (int)Math.round(100*Math.random());
t1 = System.nanoTime();
for (int i=0; i<RUNS; i++) {
test1.changeThing(i);
test2.changeThing(i);
}
t2 = System.nanoTime();
System.out.println((t2-t1) + " How long NO collection");
ArrayList<Test> list = new ArrayList<Test>(1);
list.add(test1);
list.add(test2);
// tried this too: helps a tiny tiny bit
list.trimToSize();
t1= System.nanoTime();
for (int i=0; i<RUNS; i++) {
for (Test eachTest : list) {
eachTest.changeThing(i);
}
}
t2 = System.nanoTime();
System.out.println((t2-t1) + " How long collection");
Test[] array = new Test[2];
list.toArray(array);
t1= System.nanoTime();
for (int i=0; i<RUNS; i++) {
for (Test test : array) {
test.changeThing(i);
}
}
t2 = System.nanoTime();
System.out.println((t2-t1) + " How long array ");
}
}
class Test {
int thing;
int thing2;
public void changeThing(int addThis) {
thing2 = addThis + thing;
}
}
解决方案
微基准测试是非常,非常难以获得正确的平台喜欢Java。你肯定已经取代码基准入单独的方法、运行他们几千倍的热身,然后测量。我做了那(代码下面)以及结果是,直接通过引用的是后三次尽快通过的一个阵列,但是收集仍然是缓慢的一个因素2.
这些数字是基于JVM的选择 -server -XX:+DoEscapeAnalysis
.没有 -server
, 使用集合 大幅 慢(但奇怪的是,直接和一系列的访问是很快一点,表示有一些奇怪的会上)。 -XX:+DoEscapeAnalysis
产生的另一个30%的加速收集,但很多questionabled是否会的工作,以及对实际生产的代码。
总的我的结论是:忘了微基准测试,他们可以很容易被误导。衡量接近以产品代码为你可以没有必要重写你的整个应用程序。
import java.util.ArrayList;
public class ArrayTest {
static int RUNS_INNER = 1000;
static int RUNS_WARMUP = 10000;
static int RUNS_OUTER = 100000;
public static void main(String[] args) {
long t1;
long t2;
Test test1 = new Test();
test1.thing = (int)Math.round(100*Math.random());
Test test2 = new Test();
test2.thing = (int)Math.round(100*Math.random());
for(int i=0; i<RUNS_WARMUP; i++)
{
testRefs(test1, test2);
}
t1 = System.nanoTime();
for(int i=0; i<RUNS_OUTER; i++)
{
testRefs(test1, test2);
}
t2 = System.nanoTime();
System.out.println((t2-t1)/1000000.0 + " How long NO collection");
ArrayList<Test> list = new ArrayList<Test>(1);
list.add(test1);
list.add(test2);
// tried this too: helps a tiny tiny bit
list.trimToSize();
for(int i=0; i<RUNS_WARMUP; i++)
{
testColl(list);
}
t1= System.nanoTime();
for(int i=0; i<RUNS_OUTER; i++)
{
testColl(list);
}
t2 = System.nanoTime();
System.out.println((t2-t1)/1000000.0 + " How long collection");
Test[] array = new Test[2];
list.toArray(array);
for(int i=0; i<RUNS_WARMUP; i++)
{
testArr(array);
}
t1= System.nanoTime();
for(int i=0; i<RUNS_OUTER; i++)
{
testArr(array);
}
t2 = System.nanoTime();
System.out.println((t2-t1)/1000000.0 + " How long array ");
}
private static void testArr(Test[] array)
{
for (int i=0; i<RUNS_INNER; i++) {
for (Test test : array) {
test.changeThing(i);
}
}
}
private static void testColl(ArrayList<Test> list)
{
for (int i=0; i<RUNS_INNER; i++) {
for (Test eachTest : list) {
eachTest.changeThing(i);
}
}
}
private static void testRefs(Test test1, Test test2)
{
for (int i=0; i<RUNS_INNER; i++) {
test1.changeThing(i);
test2.changeThing(i);
}
}
}
class Test {
int thing;
int thing2;
public void changeThing(int addThis) {
thing2 = addThis + thing;
}
}
其他提示
你的基准,才有效,如果实际使用情况相匹配的基准代码,即很少几个操作上的每一个元素,以便执行时间在很大程度上决定访问的时间,而不是操作自己。如果是这种情况,那么是的,你应该使用数组如果性能是至关重要的。然而,如果你真正的使用情况涉及到大量更多的实际计算每件,然后访问时间为每件将成为很多较不显着。
它可能是无效的。如果我理解的方式,即编译工作,编制一个方法不会影响到一个电话到这种方法已经执行。由于 main
方法只是所谓的一次,它将最终被解释,并且由于大多数工作是在体的方法,这个数字你不会特别指示的正常执行。
JIT汇编的效果可能有助于解释为什么没有收集的情况是速度较慢,该阵列的情况。这种结果是违反直觉的,它的地方一个怀疑上的其他基准结果的报告。