当前位置: 首页 > 面试题库 >

-Xmx和Runtime.maxMemory为什么不一致

竺捷
2023-03-14
问题内容

当您添加

 -Xmx????m

在命令行中,JVM给您提供了一个接近此值的堆,但最多可以出14%。JVM可以使您更接近所需的数字,但只能通过反复试验才能实现。

 System.out.println(Runtime.getRuntime().maxMemory());

版画

-Xmx1000m ->  932184064
-Xmx1024m -Xmx1g ->  954728448
-Xmx1072m ->  999292928
-Xmx1073m -> 1001390080

我正在运行HotSpot Java 8 Update 5。

显然,堆可以在上面,1000000000但是为什么要这样-Xmx1073m而不是说呢-Xmx1000m

BTW 1g== 1024m表示1g应该为1024 ^ 3,比1000 ^ 3高7%,但您得到的东西比1000 ^ 3低7%。

太多的变化表明我缺少关于堆如何工作的一些基本知识。如果我要求-
Xmx1000m,而1001390080我不在乎,我会假设它需要遵守一些分配倍数,但是给你932184064建议我,堆比我想象的要复杂。

编辑我发现

-Xmx1152m gives 1073741824 which is exactly 1024^3

因此看来,这比我在maxMemory()情况下所要求的要少128 MB。

BTW 128是我最喜欢的号码。我今天在街道号码的一次会议上,128演讲者引用了书中的一本书128;)


问题答案:

差异似乎是由垃圾收集器的幸存者空间的大小引起的。

如docs中-Xmx所述,该标志控制内存分配池的最大大小。内存分配池的堆部分分为Eden,Survivor和Tenured空间。正如描述的这个答案,有两个幸存者的区域,只有其中之一是可在任何给定时间点要hold住对象。因此,如报告的那样,可用于分配对象的总表观空间必须从总堆内存池中减去幸存者空间之一的大小。Runtime.maxMemory()

您可以使用MemoryMXBeanMemoryPoolMXBean类来获取有关内存分配的更多信息。这是我编写的一个简单程序:

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryPoolMXBean;

public class MemTest {
  static String mb (long s) {
    return String.format("%d (%.2f M)", s, (double)s / (1024 * 1024));
  }

  public static void main(String[] args) {
    System.out.println("Runtime max: " + mb(Runtime.getRuntime().maxMemory()));
    MemoryMXBean m = ManagementFactory.getMemoryMXBean();

    System.out.println("Non-heap: " + mb(m.getNonHeapMemoryUsage().getMax()));
    System.out.println("Heap: " + mb(m.getHeapMemoryUsage().getMax()));

    for (MemoryPoolMXBean mp : ManagementFactory.getMemoryPoolMXBeans()) {
      System.out.println("Pool: " + mp.getName() + 
                         " (type " + mp.getType() + ")" +
                         " = " + mb(mp.getUsage().getMax()));
    }
  }
}

在OpenJDK 7上,此输出java -Xmx1024m MemTest为:

Runtime max: 1037959168 (989.88 M)
Non-heap: 224395264 (214.00 M)
Heap: 1037959168 (989.88 M)
Pool: Code Cache (type Non-heap memory) = 50331648 (48.00 M)
Pool: Eden Space (type Heap memory) = 286326784 (273.06 M)
Pool: Survivor Space (type Heap memory) = 35782656 (34.13 M)
Pool: Tenured Gen (type Heap memory) = 715849728 (682.69 M)
Pool: Perm Gen (type Non-heap memory) = 174063616 (166.00 M)

请注意,Eden + 2 * Survivor + Tenured = 1024M,这恰好是命令行上请求的堆空间量。非常感谢@ Absurd-
Mind指出这一点。

您在不同的JVM之间观察到的差异很可能是由于选择不同版本的默认相对大小的启发式方法不同。如本文所述(适用于Java
6,无法找到更新的版本),可以使用-XX:NewRatio-XX:SurvivorRatio标志来显式控制这些设置。因此,运行命令:

java -Xmx1024m -XX:NewRatio=3 -XX:SurvivorRatio=6

您要告诉JVM:

Young:Tenured = (Eden + 2*Survivor):Tenured = 1:3 = 256m:768m
Survivor:Eden = 1:6 = 32m:192m

因此,使用这些参数,请求-Xmx值与报告的可用内存之间的差Runtime.maxMemory()应为32m,可使用上述程序进行验证。现在,您应该能够准确地预测Runtime给定的命令行参数集报告的可用内存,这是您真正想要的,对吧?



 类似资料:
  • 添加时 对于命令行,JVM会给出一个接近于该值的堆,但最多可以超出14%。JVM可以给出一个更接近您所想要的数字,但只能通过反复试验。 显然,堆可以是上面的东西,但为什么这个而不是呢? BTW==表示应为1024^3,比1000^3高7%,但您得到的值比1000^3低7%。 偏离了这么多,表明我缺少了关于堆工作方式的一些基本知识。如果我请求-xmx1000m,而它是我不会在意,我会假设它需要遵守某

  • 问题内容: 我期望Runtime.maxMemory()完全返回-Xmx,但是它返回一个较低的值。那么它返回什么呢? 问题答案: -Xmx标志的解释取决于VM。包括HotSpot在内的某些VM会对该选项的有效值施加下限。CCC提案不应以这种方式提及-Xmx标志。 参考

  • 问题内容: 我运行以下方法Runtime.getRuntime()。maxMemory()并给出了85196800。 但是,然后我从命令行运行了top,它显示了 那不是显示使用了156M的内存吗?有什么想法吗? 问题答案: 从文档中 maxMemory()-返回Java虚拟机将尝试使用的最大内存量。 顶部仅显示系统已分配给该进程的(虚拟)内存量-您在询问Java在最坏的情况下可以尝试使用多少内存。

  • JVM选项: 正如预期的那样,JVM将为JVM堆分配将近20MB的内存。 但请参阅以下 GC 详细信息: PSYoungGen总计9216K,已用4612k[0x 00000000 ff 6000000,0x 0000000010000000100000000]< br > Eden空间8192K,56%已用[0x 000000000 ff 600000,0x 0000000 FFA 812d 8

  • 问题内容: 什么意思 问题答案: 指定内存分配池的最大大小(以字节为单位)。此值必须是大于2 MB的1024的倍数。追加字母k或K表示千字节,或者追加m或M表示兆字节。默认值为64MB。在Solaris 7和Solaris 8 SPARC平台上,此值的上限约为4000m,在Solaris 2.6和x86平台上,该值的上限约为2000m(减去开销)。例子: 因此,简单来说,就是将Java堆内存从可用

  • 蒙戈 从这一资源中,我理解了为什么mongo不是基于以下陈述的 MongoDB支持“单主”模型。这意味着您有一个主节点和多个从节点。如果主人倒台,其中一个奴隶被选为主人。这个过程会自动进行,但需要时间,通常为10-40秒。在新领导人选举期间,您的副本集已关闭,无法进行写入 是否出于同样的原因,Mongo被称为(因为写入没有发生,所以返回系统中的最新数据),但不是(不适用于写入)? 在重新选择和写入