假设有以下的Java内存配置
-Xmx2048m -Xms512m
当内存使用量超过512m时,虚拟机会有什么行为?它是否遵循特定算法?例如,它是否直接达到最大值,是否加倍,是否按增量递增,或者只在需要内存时分配?这是一个多么昂贵的操作?
我特别关注Oracle/Sun JVM 1.6版本。我认为这应该在Oracle网站上有记录,但我找不到。
假设有以下的Java内存配置
-Xmx2048m -Xms512m
现代平台上的典型值约为40,因此如果您从512MB开始,并且剩余不到40%的空间,表示超过了308MB左右,它将增加到再次有40%的空闲空间。例如,收集后仍然有400MB的活动对象,则堆将增加到约667MB。 (是的,它被命名为“ratio”,但需要一个%值作为参数...我也不知道!)
请注意,这有点不精确,垃圾收集器是“分代”的,实际上可以调整单个代的大小,但它还具有强制性的代大小之间的比率,如果您的对象在大致估计的长寿和短寿之间分布,则对于概略计算而言效果相当好。
这适用于Java 6中的默认值。如果您使用自定义垃圾收集器配置,则可能会有所不同。您可以在此处阅读有关此事的更多信息:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html#generation_sizing.total_heap
(该操作的“成本”取决于操作系统和其他正在进行的操作。如果系统负载过重,操作系统必须进行一些交换以为您创建一个连续的内存块,则可能非常昂贵!)
-verbose:gc
和/或-XX:+PrintGCDetails
选项,可以给您提供许多更详细的细节。-verbose:gc
选项的示例输出:[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
325407K->83000K
)分别表示垃圾回收前和回收后存活对象的大小总和。在小型集合之后,大小包括一些垃圾对象(不再存活),但不能被回收。这些对象要么包含在老年代中,要么从老年代或永久代引用。(776768K)
)是堆的承诺大小:可用于Java对象而无需从操作系统请求更多内存的空间量。请注意,此数字不包括其中一个幸存者空间,因为任何时候只能使用一个空间,并且还不包括持有虚拟机使用的元数据的永久代。0.2300771秒
)表示执行集合所需的时间;在本例中约为四分之一秒。需要注意的是,JVM在初始化时虚拟保留最大地址空间,但不分配物理内存。通常,JVM会将空间分配到旧代和新生代中。在新生代中有中间空间。调用的新对象包含在新生代中。
当中间空间填满时,会调用GC,将引用对象移动到称为Survivor Space的新生代段中的一个中间空间。GC可能会遵循“停止世界”保存线程状态算法或进程继续运行的算法。
当Survivor空间填满时,JVM会调用完整的GC。