Java OutOfMemoryError异常行为

叶夫根尼(Evgeniy Dorofeev):

假设我们的最大内存为256M,为什么此代码起作用:

public static void main(String... args) {
  for (int i = 0; i < 2; i++)
  {
      byte[] a1 = new byte[150000000];
  }
  byte[] a2 = new byte[150000000];
}

但是这个丢了一个OOME吗?

public static void main(String... args) {
  //for (int i = 0; i < 2; i++)
  {
      byte[] a1 = new byte[150000000];
  }
  byte[] a2 = new byte[150000000];
}
Marko Topolnik:

为了使事情更直观,请考虑使用以下代码运行此代码-Xmx64m

static long sum;
public static void main(String[] args) {
  System.out.println("Warming up...");
  for (int i = 0; i < 100_000; i++) test(1);
  System.out.println("Main call");
  test(5_500_000);
  System.out.println("Sum: " + sum);
}

static void test(int size) {
//  for (int i = 0; i < 1; i++)
  {
    long[] a2 = new long[size];
    sum += a2.length;
  }
  long[] a1 = new long[size];
  sum += a1.length;
}

根据您要进行预热还是不进行预热,它会吹还是不吹。这是因为JITted代码正确地null选择了var,而解释后的代码却没有。在Java语言规范中,这两种行为都是可以接受的,这意味着您受此约束。

Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)在OS X上进行了测试

字节码分析

查看带有for循环的字节码(简单代码,不带sum变量):

static void test(int);
  Code:
   0: iconst_0
   1: istore_1
   2: goto  12
   5: iload_0
   6: newarray long
   8: astore_2
   9: iinc  1, 1
   12:  iload_1
   13:  iconst_1
   14:  if_icmplt 5
   17:  iload_0
   18:  newarray long
   20:  astore_1
   21:  return

没有:

static void test(int);
  Code:
   0: iload_0
   1: newarray long
   3: astore_1
   4: iload_0
   5: newarray long
   7: astore_1
   8: return

没有明确的nullING出在这两种情况下,但要注意的是,在没有对例如相同的内存位置实际上是重复使用,与此相反例子。如果有的话,这将导致与观察到的行为相反的期望。

twist ...

根据我们从字节码中学到的知识,尝试运行以下代码:

public static void main(String[] args) {
  {
    long[] a1 = new long[5_000_000];
  }
  long[] a2 = new long[0];
  long[] a3 = new long[5_000_000];
}

没有抛出OOME注释掉的声明a2,它又回来了。我们分配更多,但占用更少看一下字节码:

public static void main(java.lang.String[]);
  Code:
     0: ldc           #16                 // int 5000000
     2: istore_1      
     3: ldc           #16                 // int 5000000
     5: newarray       long
     7: astore_2      
     8: iconst_0      
     9: newarray       long
    11: astore_2      
    12: ldc           #16                 // int 5000000
    14: newarray       long
    16: astore_3      
    17: return        

用于的位置2 a1被重复使用a2OP的代码也是如此,但是现在我们使用对无害零长度数组的引用来覆盖该位置,并使用另一个位置来存储对庞大数组的引用。

把它们加起来...

Java语言规范没有指定必须收集任何垃圾对象,而JVM规范仅说在完成方法后,带有局部变量的“框架”将被整体销毁。因此,我们目睹的所有行为都是本书所为。对象不可见状态(在与keppil链接的文档中提到)只是描述在某些实现中和某些情况下会发生什么情况的一种方式,但绝不是任何规范行为。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章