Java:声明大小为 n 的数组需要多长时间?

发布于 2024-11-01 14:50:21 字数 96 浏览 3 评论 0原文

在Java中声明一个大小为n的数组的运行时间是多少?我想这取决于内存是否在垃圾回收时清零(在这种情况下它可能是 O(1) )或在初始化时清零(在这种情况下它必须是 O(n) )。

What is the running time of declaring an array of size n in Java? I suppose this would depend on whether the memory is zero'ed out on garbage collection (in which case it could be O(1) ) or on initialization (in which case it'd have to be O(n) ).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

戴着白色围巾的女孩 2024-11-08 14:50:21

这是O(n)。考虑这个简单的程序:

public class ArrayTest {

  public static void main(String[] args) {
     int[] var = new int[5];
  }

}

生成的字节码是:

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

public static void main(java.lang.String[]);
  Code:
   0:   iconst_5
   1:   newarray int
   3:   astore_1
   4:   return

}

要查看的指令是 newarray 指令(只需搜索 newarray)。来自虚拟机规范:

从垃圾回收堆中分配一个新数组,其组件类型为 atype,长度为 count。这个新数组对象的引用 arrayref 被推入操作数堆栈。 新数组的每个元素都被初始化为数组类型的默认初始值 (§2.5.1)。

由于每个元素都被初始化,因此需要 O( n) 时间。

编辑

查看提供的链接,可以在恒定时间内使用默认值实现数组初始化。所以我想这最终取决于 JVM。您可以做一些粗略的基准测试来看看是否是这种情况。

It's O(n). Consider this simple program:

public class ArrayTest {

  public static void main(String[] args) {
     int[] var = new int[5];
  }

}

The bytecode generated is:

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

public static void main(java.lang.String[]);
  Code:
   0:   iconst_5
   1:   newarray int
   3:   astore_1
   4:   return

}

The instruction to take a look at is the newarray instruction (just search for newarray). From the VM Spec:

A new array whose components are of type atype and of length count is allocated from the garbage-collected heap. A reference arrayref to this new array object is pushed into the operand stack. Each of the elements of the new array is initialized to the default initial value for the type of the array (§2.5.1).

Since each element is being initialized, it would take O(n) time.

EDIT

Looking at the link amit provided, it is possible to implement array-initialization with a default value, in constant time. So I guess it ultimately depends on the JVM. You could do some rough benchmarking to see if this is the case.

梦开始←不甜 2024-11-08 14:50:21

JRE1.6 上的一个小型非专业基准测试:

public static void main(String[] args) {
    long start = System.nanoTime();
    int[] x = new int[50];
    long smallArray = System.nanoTime();
    int[] m = new int[1000000];
    long bigArray = System.nanoTime();
    System.out.println("big:" +  new Long( bigArray - smallArray));
    System.out.println("small:" +  new Long( smallArray - start));


}

给出了以下结果:

big:6133612
small:6159

所以我假设 O(n)。
当然,这还不够确定,但这是一个提示。

A small none professional benchmark on JRE1.6:

public static void main(String[] args) {
    long start = System.nanoTime();
    int[] x = new int[50];
    long smallArray = System.nanoTime();
    int[] m = new int[1000000];
    long bigArray = System.nanoTime();
    System.out.println("big:" +  new Long( bigArray - smallArray));
    System.out.println("small:" +  new Long( smallArray - start));


}

gave the following result:

big:6133612
small:6159

so I assume O(n).
of course, it is not enough to be sure, but it's a hint.

初熏 2024-11-08 14:50:21

我很确定它是 O(n),因为内存是在分配数组时初始化的。它不应该高于 O(n),而且我看不出有什么办法可以使它小于 O(n),所以这似乎是唯一的选择。

进一步详细说明,Java 在分配时初始化数组。没有办法在不遍历内存区域的情况下将其清零,并且该区域的大小决定了指令的数量。因此,下界是 O(n)。此外,使用比线性慢的归零算法是没有意义的,因为存在线性解,因此上限必须是 O(n)。因此,O(n) 是唯一有意义的答案。

不过,只是为了好玩,想象一下一个奇怪的硬件,其中操作系统可以控制各个内存区域的电源,并且可以通过关闭然后打开电源来将某个区域归零。这看起来像是 O(1) 。但在效用消失之前,区域只能这么大(不想失去一切),因此要求将区域归零仍然是 O(n) 且除数很大。

I am pretty sure that it is O(n), as the memory is initialized when the array is allocated. It should not be higher than O(n), and I can see no way to make it less than O(n), so that seems the only option.

To elaborate further, Java initializes arrays on allocation. There is no way to zero a region of memory without walking across it, and the size of the region dictates the number of instructions. Therefore, the lower bound is O(n). Also, it would make no sense to use a zeroing algorithm slower than linear, since there is a linear solution, so the upper bound must be O(n). Therefore, O(n) is the only answer that makes sense.

Just for fun, though, imagine a weird piece of hardware where the OS has control over the power to individual regions of memory and may zero a region by flipping the power off and then on. This seems like it would be O(1). But a region can only be so large before the utility disappears (wouldn't want to lose everything), so asking to zero a region will still be O(n) with a large divisor.

宁愿没拥抱 2024-11-08 14:50:21

我们来测试一下。

class ArrayAlloc {
  static long alloc(int n) {
    long start = System.nanoTime();
    long[] var = new long[n];
    long total = System.nanoTime() - start;
    var[n/2] = 8;
    return total;
  }
  public static void main(String[] args) {
    for(int i=1; i<100000000; i+=1000000) {
      System.out.println(i + "," + alloc(i));
    }
  }
}

我的 Linux 笔记本电脑(i7-4600M @ 2.90GHz)上的结果:

初始化大小为 n 的 java 数组所花费的时间

所以它显然看起来像 O(n),但是看起来它还切换到了大约 500 万个元素的更有效的方法。

Let's just test it.

class ArrayAlloc {
  static long alloc(int n) {
    long start = System.nanoTime();
    long[] var = new long[n];
    long total = System.nanoTime() - start;
    var[n/2] = 8;
    return total;
  }
  public static void main(String[] args) {
    for(int i=1; i<100000000; i+=1000000) {
      System.out.println(i + "," + alloc(i));
    }
  }
}

And the results on my linux laptop (i7-4600M @ 2.90GHz):

Time taken by the initialization of a java array of size n

So it clearly looks like O(n), but it also looks like it switches to a more efficient method at around 5 million elements.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文