为什么 Java 堆的最大大小是固定的?
它 是 不 可能在VM启动后增加Java堆的最大大小.造成这种情况的技术原因是什么?垃圾收集算法是否依赖于使用固定数量的内存?还是出于安全原因,通过消耗所有可用内存来防止 Java 应用程序对系统上的其他应用程序执行 DOS 操作?
It is not possible to increase the maximum size of Java's heap after the VM has started. What are the technical reasons for this? Do the garbage collection algorithms depend on having a fixed amount of memory to work with? Or is it for security reasons, to prevent a Java application from DOS'ing other applications on the system by consuming all available memory?
推荐答案
在 Sun 的 JVM 中,最后我知道,整个堆必须分配在一个连续的地址空间中.我想对于大堆值,在启动后添加到您的地址空间同时确保它保持连续是非常困难的.您可能需要在启动时获取它,或者根本不需要.因此,它是固定的.
In Sun's JVM, last I knew, the entire heap must be allocated in a contiguous address space. I imagine that for large heap values, it's pretty hard to add to your address space after startup while ensuring it stays contiguous. You probably need to get it at startup, or not at all. Thus, it is fixed.
即使没有立即使用,整个堆的地址空间也会在启动时保留.如果它不能为您传递的 -Xmx 的值保留足够大的连续地址空间块,它将无法启动.这就是为什么很难在 32 位 Windows 上分配大于 1.4GB 的堆的原因——因为很难找到该大小或更大的连续地址空间,因为某些 DLL 喜欢在某些地方加载,从而使地址空间碎片化.当您使用 64 位时,这不是一个真正的问题,因为有更多的地址空间.
Even if it isn't all used immediately, the address space for the entire heap is reserved at startup. If it cannot reserve a large enough contiguous block of address space for the value of -Xmx that you pass it, it will fail to start. This is why it's tough to allocate >1.4GB heaps on 32-bit Windows - because it's hard to find contiguous address space in that size or larger, since some DLLs like to load in certain places, fragmenting the address space. This isn't really an issue when you go 64-bit, since there is so much more address space.
这几乎肯定是出于性能原因.我找不到一个很好的链接来详细说明这一点,但这是 Peter Kessler 的一个很好的引用 (full链接 - 请务必阅读我在搜索时发现的评论).我相信他在 Sun 从事 JVM 方面的工作.
This is almost certainly for performance reasons. I could not find a terrific link detailing this further, but here is a pretty good quote from Peter Kessler (full link - be sure to read the comments) that I found when searching. I believe he works on the JVM at Sun.
我们需要连续内存的原因堆的区域是我们有一个一堆边数据结构由(缩放的)偏移量索引堆的开始.例如,我们跟踪对象引用更新一个字节的卡片标记数组"对于每 512 字节的堆.什么时候我们在我们拥有的堆中存储一个引用标记相应的字节卡片标记数组.我们右移商店的目的地地址和用它来索引卡片标记数组.有趣的寻址算术游戏不能在 Java 中做到(有to :-) 玩 C++.
The reason we need a contiguous memory region for the heap is that we have a bunch of side data structures that are indexed by (scaled) offsets from the start of the heap. For example, we track object reference updates with a "card mark array" that has one byte for each 512 bytes of heap. When we store a reference in the heap we have to mark the corresponding byte in the card mark array. We right shift the destination address of the store and use that to index the card mark array. Fun addressing arithmetic games you can't do in Java that you get to (have to :-) play in C++.
这是在 2004 年 - 我不确定从那以后发生了什么变化,但我很确定它仍然存在.如果你使用 Process Explorer 之类的工具,你可以看到 Java 应用程序的虚拟大小(添加虚拟大小和私有大小内存列)包括从启动点开始的总堆大小(加上其他所需的空间,毫无疑问),即使进程使用"的内存在堆开始填满之前不会接近...
This was in 2004 - I'm not sure what's changed since then, but I am pretty sure it still holds. If you use a tool like Process Explorer, you can see that the virtual size (add the virtual size and private size memory columns) of the Java application includes the total heap size (plus other required space, no doubt) from the point of startup, even though the memory 'used' by the process will be no where near that until the heap starts to fill up...
相关文章