在Java中内联声明数组是否更快(或更优)? [英] Is it faster (or better) to declare an array inline in Java?

查看:92
本文介绍了在Java中内联声明数组是否更快(或更优)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下两个几乎相等的方法调用.注意字节数组在两者上的声明和分配方式.

Consider the following two method calls that are nearly equivalent. Take note of the way the byte array is declared and allocated on both.

void Method1()
{
    byte [] bytearray = new byte[16];

    /* some code */

}

void Method2()
{
    byte [] bytearray = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

    /* some code */    
}

在两种情况下,都假定当Method1和Method2返回时,"bytearray"是垃圾回收的候选对象,因为任何操作bytearray变量的代码都不会保存方法本身末尾的引用.

In both cases, assume that when Method1 and Method2 return, "bytearray" is a candidate for garbage collection since none of the code that manipulates the bytearray variable will be holding a reference past the end of the method itself.

Method2是否通过避免调用"new"来更快(或不同地)运行?还是上述两种实现等效?在这两种情况下,Java编译器或运行时都可以进行优化以避免这种短暂的临时缓冲区的内存分配器开销吗?

Does Method2 operate any faster (or differently) by avoiding the call to "new"? Or are the two implementations above equivalent? In either case, can the Java compiler or runtime make an optimization to avoid the overhead of hitting the memory allocator for this short-lived temporary buffer?

推荐答案

哪种格式最快?取决于JIT-它们可能等效.如果有的话,很少有程序会注意到差异.

Which form is the fastest? Depends on the JIT - it's possible they're equivalent. Very few, if any, programs will ever notice the difference if there is any.

哪种形式是最好的?几乎总是使您的程序更具可读性的一种形式.

Which form is the best? Almost invariably, the one that leaves your program more readable.

但是,无论我们是否会注意到,实际有什么区别吗?让我们看看!

But is there any actual difference, regardless of if we'll ever notice? Let's have a look!

class ArrayTest {

    public int[] withNew() {
        int[] arr = new int[4];
        return arr;
    }

    public int[] withInitializer() {
        int[] arr = {0, 0, 0, 0};
        return arr;
    }

}

我们用javap -c ArrayTest对此进行反汇编:

We disassemble this with javap -c ArrayTest:

Compiled from "ArrayTest.java"
class ArrayTest {
  ArrayTest();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public int[] withNew();
    Code:
       0: iconst_4      
       1: newarray       int
       3: astore_1      
       4: aload_1       
       5: areturn       

  public int[] withInitializer();
    Code:
       0: iconst_4      
       1: newarray       int
       3: dup           
       4: iconst_0      
       5: iconst_0      
       6: iastore       
       7: dup           
       8: iconst_1      
       9: iconst_0      
      10: iastore       
      11: dup           
      12: iconst_2      
      13: iconst_0      
      14: iastore       
      15: dup           
      16: iconst_3      
      17: iconst_0      
      18: iastore       
      19: astore_1      
      20: aload_1       
      21: areturn       
}

不是,在这种情况下它们是不一样的-使用初始化形式会导致插槽分别设置为0,这是毫无意义的,因为它们已经被数组分配归零了.因此,它基本上等效于此:

Nope, they're not the same in this case - using the initializer form causes the slots to be individually set to 0, which is kind of pointless since they're already zeroed by the array allocation. So, it's basically equivalent to this:

public int[] withNewAndSettingExplicitly() {
    int[] arr = new int[4];
    arr[0] = 0;
    arr[1] = 0;
    arr[2] = 0;
    arr[3] = 0;
    return arr;
}

尽管可以编译为另一组字节代码,这些字节代码基本相同,但不完全相同:

although that compiles to yet another set of byte code, which is mostly the same but not quite:

  public int[] withNewAndSettingExplicitly();
    Code:
       0: iconst_4      
       1: newarray       int
       3: astore_1      
       4: aload_1       
       5: iconst_0      
       6: iconst_0      
       7: iastore       
       8: aload_1       
       9: iconst_1      
      10: iconst_0      
      11: iastore       
      12: aload_1       
      13: iconst_2      
      14: iconst_0      
      15: iastore       
      16: aload_1       
      17: iconst_3      
      18: iconst_0      
      19: iastore       
      20: aload_1       
      21: areturn 

因此,故事的寓意是这样的:如果您希望将所有元素设置为0,则使用new int[size]生成的字节码更少(可能更快,也可能不会更快),但是您还必须输入更少(恕我直言是一个大胜利).如果要在分配数组时直接在数组中设置值,请使用代码中看起来最好的东西,因为无论选择哪种形式,生成的代码都几乎相同.

Thus, the moral of the story is this: If you want all elements set to 0, you're generating less bytecode with new int[size] (which may or may not be faster), but you also have to type less (which imho is a big win). If you want to set the values in the array directly when you're allocating it, use whatever looks best in your code, because the generated code will be pretty much the same whatever form you choose.

现在,回答您的实际问题:

Now, to answer your actual questions:

Method2是否通过避免调用"new"来更快(或不同地)运行?

Does Method2 operate any faster (or differently) by avoiding the call to "new"?

如我们所见,new只是隐藏在初始化程序语法的后面(查找newarray op代码).顺便说一下,在JVM中分配非常便宜(代垃圾收集器具有令人愉悦的副作用).

As we saw, the new is just hidden behind the initializer syntax (look for the newarray op code). By the way, allocation is extremely cheap in the JVM (generational garbage collectors have that pleasant side effect).

还是上面的两个实现是等效的?

Or are the two implementations above equivalent?

正如我们所看到的-不完全是,但是几乎没有人会注意到差异.

As we saw - not quite, but it's unlikely anyone will ever notice the difference.

在任何一种情况下,Java编译器或运行时都可以进行优化,以避免为这个短暂的临时缓冲区占用内存分配器的开销吗?

In either case, can the Java compiler or runtime make an optimization to avoid the overhead of hitting the memory allocator for this short-lived temporary buffer?

再次-分配很便宜,所以不用担心.不过,最近的JVM具有称为

Again - allocation is cheap, so don't worry. Nevertheless, recent JVMs have this little feature called escape analysis which may result in the array being stack allocated rather than heap allocated.

这篇关于在Java中内联声明数组是否更快(或更优)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆