Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/338.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 使用JIT编译器执行Collections.emptyList和empty ArrayList_Java_Performance_Jit_Jvm Hotspot - Fatal编程技术网

Java 使用JIT编译器执行Collections.emptyList和empty ArrayList

Java 使用JIT编译器执行Collections.emptyList和empty ArrayList,java,performance,jit,jvm-hotspot,Java,Performance,Jit,Jvm Hotspot,使用Collections.emptyList()或空ArrayList之间是否存在性能差异,尤其是在使用JIT编译器时 我可以想象,例如,JIT编译器不进行内联或静态方法调用,因为执行的方法取决于类型 编辑 我知道Collections.emptyList()返回一个不可变列表,而ArrayList是可变对象 我的意思是,如果我将一个或另一个作为参数传递给一个方法,而该方法不修改列表,这是否限制了JIT编译器优化该方法的可能性 一个简单的例子(只是为了澄清我的意思): int和(列表) { 整

使用
Collections.emptyList()
或空
ArrayList
之间是否存在性能差异,尤其是在使用JIT编译器时

我可以想象,例如,JIT编译器不进行内联或静态方法调用,因为执行的方法取决于类型

编辑 我知道
Collections.emptyList()
返回一个不可变列表,而
ArrayList
是可变对象

我的意思是,如果我将一个或另一个作为参数传递给一个方法,而该方法不修改列表,这是否限制了JIT编译器优化该方法的可能性

一个简单的例子(只是为了澄清我的意思):

int和(列表)
{
整数和=0;
对于(int i=0;iCollections.emptyList()始终返回相同的、不可变的空列表对象(单例)。另一方面,创建ArrayList实际上会创建一个新对象,分配内存,并且该对象必须稍后进行GCed


应该没有什么显著区别,但是Collections.emptyList()工作更少。这些操作在功能上并不等效。一个允许获取不可变的空列表,而另一个允许创建新的可变列表。根据需要的功能选择一个或另一个。不是出于性能原因。

Collections.emptyList()
和empty
new ArrayList()
工作方式略有不同。集合返回的列表不仅是空的,而且是不可变的,因此每个列表都可以作为单例存储,并在每次调用emptyList()时返回(由于类型擦除,这对于任何类型限定符都是可能的)

因此,答案取决于如何处理空列表。如果要在某些代码中返回空列表作为最终值,
Collections.emptyList()
当然更好(它甚至不会创建新对象)。如果要设置空列表以进行进一步修改,
Collections.emptyList()
完全不可接受

Disclamer 以下所有内容仅适用于以下情况

简短回答 JIT编译器不执行内联或静态方法调用,因为 执行的方法取决于类型

这与事实相反。请看我的答案

使用 Collections.emptyList()或空ArrayList,尤其是在使用 JIT编译器

在极少数情况下-是的。请参阅微基准测试结果

如果我只使用ArrayList调用这个方法,JIT编译器就可以 内联ArrayList.get()。如果我还使用Collections.empty()调用 这是不可能的,对吗

简而言之,这要看情况而定。JIT编译器足够聪明,可以识别单态、双态和多形调用模式,并提供适当的实现

答复 为了得到一个详细的答案,我建议阅读以下关于方法分派的黑魔法的内容

C2基于 观察到的类型配置文件。如果只有一个接收器类型(即 是的,调用站点是单态的),它可以简单地检查 预测类型,并直接内联目标。相同的优化 如果观察到两种接收器类型(即 是的,调用站点是双晶型的),以两个分支为代价

让我们考虑下面的JMH示例(如果您还没有了解JMH,那么我建议阅读它)。 在单态和双态调用的情况下,JIT将虚拟调用替换为具体实现。例如,在

arrayList()
的情况下,我们为
-XX:+printinline
提供了以下输出:

@ 27   edu.jvm.runtime.ExampleBench::sum (38 bytes)   inline (hot)
   @ 6   java.util.ArrayList::size (5 bytes)   accessor
    \-> TypeProfile (15648/15648 counts) = java/util/ArrayList
对于
emptyList()

对于
biList()

对于
polyList()
JIT不内联任何实现,而是使用真正的虚拟调用

在这些方法中使用内联函数的优点是什么?让我们看看编译器为
arrayList()生成的代码。


正如您所看到的,JIT通过
getfield

替换了虚拟调用。JIT不关心传递给方法的列表的实际类型。它甚至不知道:您可以在10%的时间内传递空列表,在45%的时间内传递数组列表,在15%的时间内传递LinkedList,在剩余的时间内传递CopyOnWriteArrayList。这会阻止什么它来自优化方法?@JBNizet JIT编译器知道加载的字节码,因此可以知道方法是否只获取一种类型的对象。我的场景只是传递ArrayList,而不是传递ArrayList和空列表。否则你是对的。因此,你问的是,声明为
foo的方法之间的JIT是否有差异(列表)
foo(数组列表)
,对吗?如果没有,请澄清。发布代码。但是无论如何,要让你的设计干净,而不是过早地优化那些根本不需要优化的东西。Java使用脉冲形态,JIT能够处理它。不用担心。@JBNizet我曾经读到,如果只有一个实现,JIT编译器会创建不同的代码n表示接口。我想这也适用于这里。顺便说一句,我不是用它来优化,我只是想了解JIT编译器。但是列表有很多很多实现,所以它显然不适用于这里。干得好。如果你在列表中添加一些元素,比较会更相关。例如,只保留数组和bimo在双晶片测试中,将非空的ArrayList替换为包含某些元素的ArrayList,并在数组中随机交错空列表和非空列表。通过这种方式,您可能会了解这将如何减慢更真实的场景。。。
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(value = 5)
public class ExampleBench {

    @Param("10000")
    private int count;

    List<Integer>[] arrays;
    List<Integer>[] empty;
    List<Integer>[] bimorphic;
    List<Integer>[] polimorphic;

    @Setup
    public void setup(){
        Random r = new Random(0xBAD_BEEF);
        arrays = new List[count];
        empty = new List[count];
        bimorphic = new List[count];
        polimorphic = new List[count];
        for (int i = 0; i < arrays.length; i++) {
            bimorphic[i] = r.nextBoolean() ? new ArrayList<Integer>(0) : Collections.<Integer>emptyList();
            int i1 = r.nextInt(3);
            switch (i1) {
                case 0 : polimorphic[i] = new ArrayList<>(0);
                    break;
                case 1 : polimorphic[i] = new LinkedList<>();
                    break;
                case 2 : polimorphic[i] = Collections.emptyList();
                    break;
            }
            arrays[i] = new ArrayList<>(0);
            empty[i] = Collections.emptyList();
        }
    }

    @Benchmark
    public float arrayList() {
        List<Integer>[] l = arrays;
        int c = count;
        float result = 0;
        for (int i = 0; i < c; i++) {
            result += sum(l[i]);
        }
        return result;
    }

    @Benchmark
    public float emptyList() {
        List<Integer>[] l = empty;
        int c = count;
        float result = 0;
        for (int i = 0; i < c; i++) {
            result += sum(l[i]);
        }
        return result;
    }

    @Benchmark
    public float biList() {
        List<Integer>[] l = bimorphic;
        int c = count;
        float result = 0;
        for (int i = 0; i < c; i++) {
            result += sum(l[i]);
        }
        return result;
    }

    @Benchmark
    public float polyList() {
        List<Integer>[] l = polimorphic;
        int c = count;
        float result = 0;
        for (int i = 0; i < c; i++) {
            result += sum(l[i]);
        }
        return result;
    }

    int sum(List<Integer> list) {
        int sum = 0;
        for (int i = 0; i < list.size(); ++i) {
            sum += list.get(i);
        }
        return sum;
    }
}
Benchmark               (count)  Mode  Cnt       Score       Error  Units
ExampleBench.arrayList    10000  avgt    5   22902.547 ± 27665.651  ns/op
ExampleBench.biList       10000  avgt    5   50459.552 ±   739.379  ns/op
ExampleBench.emptyList    10000  avgt    5    3745.469 ±   211.794  ns/op
ExampleBench.polyList     10000  avgt    5  164879.943 ±  5830.008  ns/op
@ 27   edu.jvm.runtime.ExampleBench::sum (38 bytes)   inline (hot)
   @ 6   java.util.ArrayList::size (5 bytes)   accessor
    \-> TypeProfile (15648/15648 counts) = java/util/ArrayList
@ 27   edu.jvm.runtime.ExampleBench::sum (38 bytes)   inline (hot)
   @ 6   java.util.Collections$EmptyList::size (2 bytes)   inline (hot)
    \-> TypeProfile (9913/9913 counts) = java/util/Collections$EmptyList
@ 27   edu.jvm.runtime.ExampleBench::sum (38 bytes)   inline (hot)
   @ 6   java.util.Collections$EmptyList::size (2 bytes)   inline (hot)
   @ 6   java.util.ArrayList::size (5 bytes)   accessor
    \-> TypeProfile (2513/5120 counts) = java/util/ArrayList
    \-> TypeProfile (2607/5120 counts) = java/util/Collections$EmptyList
0x00007ff9e51bce50: cmp $0xf80036dc,%r10d     ;instance of 'java/util/ArrayList'
0x00007ff9e51bce57: jne L0000                 ;if false go to L0000 (invokeinterface size)
0x00007ff9e51bce59: mov 0x10(%rdx),%ebp       ;*getfield size optimization java.util.ArrayList::size@1 

.....

0x00007ff9e51bce6d: retq
             L0000: mov $0xffffffde,%esi      ; true virtual call starts here
0x00007ff9e51bce73: mov %rdx,(%rsp)
0x00007ff9e51bce77: callq 0x00007ff9e50051a0  ; OopMap{[0]=Oop off=92}
                                              ;*invokeinterface size
                                              ; - edu.jvm.runtime.ExampleBench::sum@6 (line 119)
                                              ;   {runtime_call}