Java 什么是更快的:创建新数组或迭代现有数组?

Java 什么是更快的:创建新数组或迭代现有数组?,java,c++,arrays,initialization,Java,C++,Arrays,Initialization,例如,我有一个数组(在Java中) 我已经使用过它,现在想要一个带零的数组。 什么会花费更少的时间:创建一个新数组(它将被初始化为零)或迭代现有数组并用零填充它 我想不管答案是什么,在C++中都是一样的。< P>你最好是填充一个现有的数组,而不是创建一个新的数组。相对而言,内存分配可能非常昂贵。事实上,如果您最喜欢的语言为您提供了保证归零的新数组,那么它可能是在幕后为您填充这些数组 也就是说,这种选择是一种微观优化。在大多数情况下,这不会产生任何明显的区别。如果你发现自己处于一个特定的案例中,你

例如,我有一个数组(在Java中)

我已经使用过它,现在想要一个带零的数组。 什么会花费更少的时间:创建一个新数组(它将被初始化为零)或迭代现有数组并用零填充它


我想不管答案是什么,在C++中都是一样的。

< P>你最好是填充一个现有的数组,而不是创建一个新的数组。相对而言,内存分配可能非常昂贵。事实上,如果您最喜欢的语言为您提供了保证归零的新数组,那么它可能是在幕后为您填充这些数组

也就是说,这种选择是一种微观优化。在大多数情况下,这不会产生任何明显的区别。如果你发现自己处于一个特定的案例中,你认为这可能会产生重要的影响,那么你最好问一个剖析器,而不是问StackOverflow

编辑我还要补充一条警告:特别是在Java这样的垃圾收集语言中,如果可以干净地进行重用,那么最好重用现有对象,而不是创建新对象。作为一般的经验法则


重新编辑。。。除非所讨论的对象预期寿命很短。可能还有一些额外的警告。回到“询问探查器”。

当创建一个新数组并用零实例化它时,速度应该会慢一些。在这种情况下,初始化和迭代就完成了。在使用现有数组的情况下,只执行迭代位。因此,使用现有数组并对其进行迭代应该会更快。当然,我们在这里讨论MS,一个新数组的初始化一般不会花费很长时间。

< P>这是一个以java为中心的答案,因为我没有C++经验。 它可能会有所不同,具体取决于您选择的方法。根据Joshua Bloch的有效Java:

最好是“…更喜欢原语而不是盒装原语,并注意无意的自动装箱”

这意味着数组被分配为

int[] array = new int[1000];
将具有更小的内存占用空间,并且比

Integer[] array = new Integer[1000];
由于不需要对
Integer
对象中的
int
值进行自动装箱

另外,请记住,创建和回收构造函数很少显式工作的小对象是便宜的,特别是在现代JVM实现中

简言之,这真的不重要。如果您对测试进行基准测试,如果差异超过几微秒,我会感到惊讶。

我已经对其进行了测试

public class Test{
  public static void main(String[] args)
 {
    int[] b = new int[1000000];
    for(int i = 0; i < b.length; i++)
        b[i] = i;

    long t1 = System.currentTimeMillis();
    int[] a = new int[1000000];
    long t2 = System.currentTimeMillis();
    System.out.println("Time to alloc: " + (double) (t2 - t1) / 1000);

    long t3 = System.currentTimeMillis();
    for(int i = 0; i < b.length; i++)
        b[i] = 0;
    long t4 = System.currentTimeMillis();
    System.out.println("Time to iterate: " + (double) (t4 - t3) / 1000);

 }
}
/*output
Time to alloc: 0.004
Time to iterate: 0.001
*/  
公共类测试{
公共静态void main(字符串[]args)
{
int[]b=新int[1000000];
for(int i=0;i

因此,我们的迭代速度大约是新分配的4倍。

尝试并对其进行基准测试,让我们知道您发现了什么。如果要将数组归零,可能有比迭代更快的方法。@Thilo,哪种方法?例如,特别是在Java中,运行时用零填充数组的速度可能比在数组上迭代要快。作为一般的经验法则,编辑有点不合适。使用分代GC进行分配的成本非常低(我认为大约是7条处理器指令),因此在这种特殊情况下,成本不会太高。此外,在一般情况下,在分代GC中,您最好创建一个新对象,而不是出于不同的原因重新使用:当GC运行时,旧一代需要移动到新GC,这可能需要内容的完整副本,而删除的对象是免费的。@DavidRodríguez dribeas:我不知道。谢谢你的评论!此外,旧的活动对象通常被移动到稳定的旧一代竞技场,以避免不断地移动它,但是如果它被更新以引用新的对象,那么一些优化就无法应用(通常GC传递只检查新一代,但如果旧对象引用新对象,则必须以不同方式跟踪它——通常只需将旧对象保留在较新的领域中,以确保在GC期间跟踪对较新对象的引用。也就是说,引用较新对象的旧对象会增加GC传递的成本在具有良好JVM的Java中比在C++中更适用:在Java中,JIT编译器(有时)可以确定它可以完全地将一个新的对象放置在本地堆栈上。这是很难或不可能在C++中安全地进行的,而且我不相信任何C++编译器会把“代码>新的< /Cord>对象放到栈上。当然,在C++中,你可以明确地指定它们位于堆栈上,java中没有的自由。@在优化中,C++中的分配器比java中的分配器慢得多,java中的分配成本(GealGealGGC)类似于C++中的堆栈分配的成本(指针偏移,并且很少额外的工作)。。由于不同的原因,该测试是虚假的。第一个原因是您如何测量时间,这几乎没有足够的精度来完成该工作。第二个原因是您在测量之前没有进行足够的处理以获得合理的结果,这可能会产生额外的成本。例如,内存可能新分配给VM并访问它以获得更多的时间第一次可能会触发代价高昂的页面错误…我并不是说测试完全没有用,但它并不是真的
public class Test{
  public static void main(String[] args)
 {
    int[] b = new int[1000000];
    for(int i = 0; i < b.length; i++)
        b[i] = i;

    long t1 = System.currentTimeMillis();
    int[] a = new int[1000000];
    long t2 = System.currentTimeMillis();
    System.out.println("Time to alloc: " + (double) (t2 - t1) / 1000);

    long t3 = System.currentTimeMillis();
    for(int i = 0; i < b.length; i++)
        b[i] = 0;
    long t4 = System.currentTimeMillis();
    System.out.println("Time to iterate: " + (double) (t4 - t3) / 1000);

 }
}
/*output
Time to alloc: 0.004
Time to iterate: 0.001
*/