java - 在 Java 中声明一个内联数组会更快(或更好)吗?

标签 java arrays inline

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

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 变量的代码都不会持有超过方法本身末尾的引用。

方法 2 是否通过避免调用“new”而运行得更快(或不同)?或者上面的两个实现是等价的?在任何一种情况下,Java 编译器或运行时是否可以进行优化以避免为这个短暂的临时缓冲区命中内存分配器的开销?

最佳答案

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

哪种形式最好?几乎无一异常(exception)地是那种能让你的程序更具可读性的形式。

但无论我们是否会注意到,是否存在任何实际差异?一起来看看吧!

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 反汇编:

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,这有点毫无意义,因为它们已经被数组分配归零。所以,它基本上等同于:

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

尽管它编译成另一组字节码,它们大部分相同但不完全相同:

  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] 生成更少的字节码(可能会或可能不会更快),但您还必须减少输入(恕我直言,这是一个巨大的胜利)。如果您想在分配数组时直接设置数组中的值,请使用代码中看起来最好的任何内容,因为无论您选择何种形式,生成的代码都几乎相同。

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

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

正如我们所见,new 只是隐藏在初始化语法后面(寻找 newarray 操作码)。顺便说一句,JVM 中的分配成本非常低(分代垃圾收集器具有令人愉快的副作用)。

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?

再一次 - 分配很便宜,所以不用担心。然而,最近的 JVM 有一个叫做 escape analysis 的小特性。这可能会导致数组被分配到堆栈而不是堆上。

关于java - 在 Java 中声明一个内联数组会更快(或更好)吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20348818/

相关文章:

java - 具有泛型的 Jackson2 编码包装器类

java - Gson:直接将String转换为JsonObject(无POJO)

java - Neo4j-OGM 关系未加载

c - 如何使用指针对结构数组进行排序?

arrays - 将数组名称作为 mongoose 中的参数传递

java - 查找数组方法的众数 (java)

c++ - 二维可变大小数组 C++

css - 为什么这不会对齐中间或底部?

html - 带有内联样式的可折叠列表 - 可能吗?

html - 如何在 twitter bootstrap 中排列我的按钮