为什么-Xmx和Runtime.maxMemory不同意 [英] Why do -Xmx and Runtime.maxMemory not agree

查看:186
本文介绍了为什么-Xmx和Runtime.maxMemory不同意的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当您添加

  -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



顺便说一句 1g == 1024m 这表明 1g 应该是1024 ^ 3,比1000 ^ 3高7%,但是比1000 ^ 3。




如此之多,表明我缺少一些有关堆的工作原理。如果我要求-Xmx1000m并且它是 1001390080 我不在乎,我会假设它有一些需要坚持的分配,但给你 932184064 表示堆比我想象的复杂。






编辑我发现

  -Xmx1152m给出1073741824这正是1024 ^ 3 

因此它看起来比我在这种情况下要求的maxmemory()要少128 MB。






BTW 128是我最喜欢的号码。我今天在一个街头号码 128 的会议上发言,演讲者从页面 128 ;>


解决方案

这个区别看起来是垃圾收集器的幸存者空间的大小造成的。



-Xmx 标志,如 docs ,控制内存分配池的最大大小。 内存分配池的堆部分分为Eden,Survivor ,和终身空间。如此答案中所述,存在两个幸存者区域,其中只有一个可用于在任何给定的时间点保存活物。因此,由 Runtime.maxMemory()报告的可用于分配对象的总表观空间必须从总堆内存池中减去其中一个存活空间的大小。 / p>

您可以使用 MemoryMXBean MemoryPoolMXBean 类来获得有关内存分配的更多信息。我写了一个简单的程序:

  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(堆:+ mb(m.getHeapMemoryUsage()。getMax())); (MemoryPoolMXBean mp:ManagementFactory.getMemoryPoolMXBeans()){
System.out.println(Pool:+ mp.getName()+
(type+

mp.getType()+)+
=+ mb(mp.getUsage()。getMax()));



$ / code $ / pre
$ b $ p java -Xmx1024m MemTest
是:

 运行时最大值:1037959168( 989.88 M)
非堆:224395264(214.00 M)
堆:1037959168(989.88 M)
代码缓存(类型非堆内存)= 50331648(48.00 M)
Pool:Eden Space(类型堆内存)= 286326784(273.06 M)
池:Survivor Space(类型堆内存)= 35782656(34.13 M)
池:Tenured Gen(类型堆内存)= 715849728(682.69 M)
池:Perm Gen(类型非堆内存)= 174063616(166.00 M)

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



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

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

您告诉JVM:

 年轻:终身=(Eden + 2 *幸存者):终身= 1:3 = 256m:768m 
幸存者:伊甸园= 1:6 = 32m:192m
-Xmx
值和 Runtime.maxMemory()报告的可用内存应该是32m,这是使用上述程序验证的。现在,您应该能够准确预测由 Runtime 报告的可用内存对于给定的一组命令行参数,这是您真正想要的,对吧? p>

When you add

 -Xmx????m

to the command line, the JVM gives you a heap which is close to this value but can be out by up to 14%. The JVM can give you a figure much closer to what you want, but only through trial and error.

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

prints

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

I am running HotSpot Java 8 update 5.

Clearly, the heap can be something just above 1000000000 but why is this -Xmx1073m instead of say -Xmx1000m?

BTW 1g == 1024m which suggests that 1g should be 1024^3 which is 7% higher than 1000^3 but you get something 7% lower than 1000^3.


Being off by so much suggests that I am missing something fundamental about how the heap works. If I asked for -Xmx1000m and it was 1001390080 I wouldn't care, I would assume there is some allocation multiple it needs to adhere to, but to give you 932184064 suggests to me the heap is more complicated than I can imagine.


EDIT I have found that

-Xmx1152m gives 1073741824 which is exactly 1024^3

so it appears it is giving me exactly 128 MB less than I asked for in this case cf the maxMemory().


BTW 128 is my favourite number. I was in a conference today at street number 128 and the speaker quoted a book from page 128 ;)

解决方案

The difference appears to be accounted for by the size of the garbage collector's survivor space.

The -Xmx flag, as described in the docs, controls maximum size of the memory allocation pool. The heap portion of the memory allocation pool is divided into Eden, Survivor, and Tenured spaces. As described in this answer, there are two survivor regions, only one of which is available to hold live objects at any given point in time. So the total apparent space available for allocating objects, as reported by Runtime.maxMemory(), must subtract the size of one of the survivor spaces from the total heap memory pool.

You can use the MemoryMXBean and MemoryPoolMXBean classes to get a little more information about your memory allocation. Here's a simple program I wrote:

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()));
    }
  }
}

The output of this on OpenJDK 7 for java -Xmx1024m MemTest is:

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)

Note that Eden + 2*Survivor + Tenured = 1024M, which is exactly the amount of heap space requested on the command line. Much thanks to @Absurd-Mind for pointing this out.

The differences you observe between different JVMs are likely due to differing heuristics for selecting the default relative sizes of the various generations. As described in this article (applies to Java 6, wasn't able to find a more recent one), you can use the -XX:NewRatio and -XX:SurvivorRatio flags to explicitly control these settings. So, running the command:

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

You're telling the JVM that:

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

So, with these parameters, the difference between the requested -Xmx value and the available memory reported by Runtime.maxMemory() should be 32m, which is verified using the above program. And now you should be able to accurately predict the available memory reported by Runtime for a given set of command-line arguments, which is all you ever really wanted, right?

这篇关于为什么-Xmx和Runtime.maxMemory不同意的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆