为什么-Xmn1m -XX:SurvivorRatio = 2使eden空间为0k

时间:2017-11-09 02:08:34

标签: java jvm java-7

我设置-Xmn1m -XX:SurvivorRatio=2,希望看到伊甸园空间为512K,但实际上是0K

真的很奇怪,我不知道为什么。我需要你的帮助。

  

vm选项:-Xmx20m -Xms20m -Xmn1m -XX:SurvivorRatio = 2   -XX:+ PrintGCDetails

     

java版本:1.7.0_79

代码和结果如下:

public class NewSizeDemo {
    public static void main(String[] args){
        byte[] b = null;

        for (int i=0; i<10; i++){
            b = new byte[1*1024*1024];
        }
    }
}
Heap
 PSYoungGen      total 512K, used 0K [0x00000007fff00000, 0x0000000800000000, 0x0000000800000000)
  eden space 0K, -2147483648% used [0x00000007fff00000,0x00000007fff00000,0x00000007fff00000)
  from space 512K, 0% used [0x00000007fff80000,0x00000007fff80000,0x0000000800000000)
  to   space 512K, 0% used [0x00000007fff00000,0x00000007fff00000,0x00000007fff80000)
 ParOldGen       total 19456K, used 11573K [0x00000007fec00000, 0x00000007fff00000, 0x00000007fff00000)
  object space 19456K, 59% used [0x00000007fec00000,0x00000007ff74d5a0,0x00000007fff00000)
 PSPermGen       total 21504K, used 2996K [0x00000007f9a00000, 0x00000007faf00000, 0x00000007fec00000)
  object space 21504K, 13% used [0x00000007f9a00000,0x00000007

2 个答案:

答案 0 :(得分:2)

我使用Java 7和Java 8以及不同的选项进行了一些实验。关键点似乎是

  • 空格的大小始终是512k的倍数,不能为空,因此最小的设置是“eden 1×512k,从1×512k到{{1 “},这意味着您的新尺寸不能小于1×512k。此外,只有1536k单位大小的整数因子才能尽可能地考虑比率约束。

  • 您指定的数字可以舍入为512k的倍数,并为每个空格强制执行512k的最小尺寸,这是第一个显示不一致的地方。例如。在Java 8中使用512k时,我收到一条警告:Xmn1m NewSize(显然已经适应)超过了1536k的{​​{1}}(显然还没有改编) ),这是令人困惑的,因为MaxNewSize应该将两者都设置为相同的值,所以说两者都太小将更容易理解。此外,警告仅在使用1024k时显示。 Xmn1m,不受四舍五入的影响,但未针对Xmn1mXmn1024k显示。

  • 由于JVM没有使用该选项崩溃,因此适配似乎总是会产生合理的值,但打印统计信息的代码似乎有错误(仅限Java 7),将尝试的配置号与JVM实际使用的数字。

  • 为Young Generation报告的总大小始终仅包含 eden 来自空间,忽略始终为空 空间,与尺寸背后报告的地址不一致,包括完整的跨度,覆盖所有三个空间。

答案 1 :(得分:2)

这是JDK 7u40-b27和JDK 7u40-b28之间引入的 JVM错误
错误报告JDK-8016309未公开。

在JDK 7u40之前,堆区域的最小大小为512字(4KB)。使用给定的JVM参数,Eden大小已正确设置为512K:

 PSYoungGen      total 768K, used 287K [0x00000000fff00000, 0x0000000100000000, 0x0000000100000000)
  eden space 512K, 56% used [0x00000000fff00000,0x00000000fff47e08,0x00000000fff80000)
  from space 256K, 0% used [0x00000000fffc0000,0x00000000fffc0000,0x0000000100000000)
  to   space 256K, 0% used [0x00000000fff80000,0x00000000fff80000,0x00000000fffc0000)

JDK-6725714将最小区域大小增加到65536字(512KB) 这是related change。同样的变化打破了上浆政策 这导致JVM的调试版本中的断言失败:

# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (/home/hotspot/src/share/vm/gc_implementation/parallelScavenge/psYoungGen.cpp:183), pid=10261, tid=1081264448
#  assert(eden_size > 0 && survivor_size > 0) failed: just checking
#

产品构建中没有断言失败,而是您观察到的奇怪行为。

在JDK 8中注意到并修复了该问题。年轻一代的最小可能大小变为1536KB。我想这个修复程序不适合后向移植,因此该错误仍然存​​在于JDK 7的后续更新中。

但是,决定在JDK 7u40 release notes中记录问题:

  

区域:hotspot / gc
  概要:新的最小年轻一代不是   由JVM正确检查。

     

在JDK 7u40中,并行的年轻代的最小尺寸   垃圾收集器在32位JVM中从192 KB增加到768 KB,   在64位JVM中为1536 KB。这个新的最小尺寸不合适   由JVM检查。如果年轻一代的尺寸小于   新的最小值在命令行中指定,它可以导致   无论是崩溃还是性能下降。

     

年轻代的大小由选项-XX:NewSize =和设置   -XX:MaxNewSize =,或选项-Xmn(后一个选项相当于将NewSize和MaxNewSize都设置为)。如果   如果不使用上面的选项,则计算年轻代的大小   作为最大堆大小的一部分。

     

解决方法:使用至少768 KB的年轻代(适用于   32位JVM)或1536 KB(用于64位JVM)。