问题描述
当您添加
-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
标志,如,控制内存分配池的最大大小。 的堆部分分为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
$ c因此,通过这些参数,所请求的 -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不同意的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!