Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ArrayList的性能_Java_Performance - Fatal编程技术网

Java ArrayList的性能

Java ArrayList的性能,java,performance,Java,Performance,我试图了解将ArrayList预初始化为给定容量与使用默认容量和按需扩展之间的性能差异。只是出于好奇。我发现默认容量数组代码比将数组初始化为所需容量的代码快约10%。以下是我使用的代码: public class Test { public static void main(String[] args) { long t1 = System.currentTimeMillis(); for(int j=0;j<10;++j) {

我试图了解将
ArrayList
预初始化为给定容量与使用默认容量和按需扩展之间的性能差异。只是出于好奇。我发现默认容量数组代码比将数组初始化为所需容量的代码快约10%。以下是我使用的代码:

public class Test {
    public static void main(String[] args) {

        long t1 = System.currentTimeMillis();
        for(int j=0;j<10;++j) {
            List<Integer> list = new ArrayList<Integer>();
            for(int i=0;i<1000000;++i) {
                list.add(i);
            }
        }
        long t2 = System.currentTimeMillis();
        System.out.println("Time taken: " + (t2-t1)/10.0);
    }
}
公共类测试{
公共静态void main(字符串[]args){
long t1=System.currentTimeMillis();

对于(int j=0;j我对此做了一些实验,我的结论是您的基准测试有缺陷。当我修复最明显的问题时,我得到了截然不同的结果。我的时间安排如下:

default list: 74ms pre-sized list: 54ms Integer array: 42ms int array: 9ms
public class Clazz {

    static final int N = 1000000;

    interface Test {
        void test();
    }
    static final class DfltListTest implements Test {
        public void test() {
            for (int j = 0; j < 10; ++j) {
                List<Integer> list = new ArrayList<Integer>();
                for (int i = 0; i < N; ++i) {
                    list.add(i);
                }
            }
        }
    }
    static final class SizedListTest implements Test {
        public void test() {
            for (int j = 0; j < 10; ++j) {
                List<Integer> list = new ArrayList<Integer>(N);
                for (int i = 0; i < N; ++i) {
                    list.add(i);
                }
            }
        }
    }
    static final class IntegerArrayTest implements Test {
        public void test() {
            for (int j = 0; j < 10; ++j) {
                Integer[] arr = new Integer[N];
                for (int i = 0; i < N; ++i) {
                    arr[i] = i;
                }
            }
        }
    }
    static final class IntArrayTest implements Test {
        public void test() {
            for (int j = 0; j < 10; ++j) {
                int[] arr = new int[N];
                for (int i = 0; i < N; ++i) {
                    arr[i] = i;
                }
            }
        }
    }

    static void test(Test t, String name) {
        final int iter = 11;
        final long timings[] = new long[iter];
        for (int k = 0; k < iter; ++k) {
            long t1 = System.currentTimeMillis();
            t.test();
            long t2 = System.currentTimeMillis();
            timings[k] = t2 - t1;
            System.gc();
        }
        Arrays.sort(timings);
        System.out.printf("%s: %dms\n", name, timings[iter / 2]);
    }

    public static void main(String[] args) {
        for (int i = 0; i < 5; ++i) {
            test(new DfltListTest(), "default list");
            test(new SizedListTest(), "pre-sized list");
            test(new IntegerArrayTest(), "Integer array");
            test(new IntArrayTest(), "int array");
        }
    }
}
我已经使用Java1.7.0\u09和
-XX:+AggressiveOpts-XX:CompileThreshold=1对它进行了测试

当我使用Java 6测试相同的代码时,排名是相同的,但是默认列表和预先调整大小的列表之间的差异要显著得多。我没有试图理解Java 7的哪些方面使得差异如此之小


有关如何对Java代码进行基准测试的一些提示,请参见

让我们做这个实验,测量不同容量列表上单个
add()
所需的时间

        ArrayList<Integer> list = new ArrayList<Integer>(N);
        for(int i=0;i<N;++i) 
            list.add(new Integer(i));  // how many ns does this take?
显然,用2M容量填写4个列表要比用8M容量填写1个列表快得多

这表明您所观察到的情况是可能的—当列表以较小的容量开始时,运行速度会更快,并且节省的时间比以后的阵列复制开销还要多

但是为什么当容量增加时它会变慢呢?我不确定。也许这与二级缓存有关。也许JVM在分配更大的阵列时有更多的开销


测试代码:

static void test(int N)
{
    long t0 = System.nanoTime();
    long x = 0;
    long t = 0;
    while(true)
    {
        ArrayList<Integer> list = new ArrayList<Integer>(N);
        for(int i=0;i<N;++i)
            list.add(new Integer(i));

        t = System.nanoTime()-t0;
        x+=N;

        if(t>1000_000_000)
            break;
    }

    System.out.printf("%8s\t%4s%n", N, t/x);
}

public static void main(String[] args)
{
    while(true)
        for(int N=1000; N<20_000_000; N*=2)
            test(N);
}
静态空隙试验(int N)
{
long t0=System.nanoTime();
长x=0;
长t=0;
while(true)
{
ArrayList=新的ArrayList(N);
对于(int i=0;i1000_000_000)
打破
}
System.out.printf(“%8s\t%4s%n”,n,t/x);
}
公共静态void main(字符串[]args)
{
while(true)

对于(int N=1000;首先,这不是一种很好的基准测试方法。您包括JIT预热时间,并且您使用的是
currentTimeMillis
而不是
nanoTime
。尝试使用-另外,我怀疑您测试的很多时间都花在装箱一百万
int
值上。尝试使用不需要创建的东西在每次迭代中创建一个新对象。这只是一个有用的提示:运行两次测试,然后查看第二次运行的结果。第一次运行经常因为VM按需加载而受到污染。我将外部循环更改为运行100次迭代,发现预分配版本的速度大约是原来的两倍。他说,大部分时间都被浪费了装箱,而不是在ArrayList上调整大小。@Raze2dust:除非您已经显著地修复了基准测试的方式,否则我仍然非常怀疑。我强烈建议您改用Caliper。(我也怀疑你还在打拳击,但是如果不看代码就很难判断。只要使用
列表和一些文字,就可以把它从等式中去掉。)关于微基准标记的链接不错。使用
字符串
而不是
整数
解决了这个“问题”。因此,自动装箱可能与其他基准测试缺陷一起在这里发挥主要作用。您能否更改答案以否定自动装箱效果?它将完成答案,我可以接受。@Raze2dust:完成。
int[]
版本比
Integer[]快4.5倍
。int更改只会影响普通数组的大小写。是否可以使用其他非自动装箱对象,如字符串或其他对象,以便在数组和列表之间公平竞争?
static void test(int N)
{
    long t0 = System.nanoTime();
    long x = 0;
    long t = 0;
    while(true)
    {
        ArrayList<Integer> list = new ArrayList<Integer>(N);
        for(int i=0;i<N;++i)
            list.add(new Integer(i));

        t = System.nanoTime()-t0;
        x+=N;

        if(t>1000_000_000)
            break;
    }

    System.out.printf("%8s\t%4s%n", N, t/x);
}

public static void main(String[] args)
{
    while(true)
        for(int N=1000; N<20_000_000; N*=2)
            test(N);
}