use*_*431 66 java 64-bit jvm memory-management virtual-memory
在我们的生产机器上运行一个简单的Java程序,我注意到这个程序占用了更多的10G virt.我知道虚拟内存不是那么相关,但至少我想了解为什么需要它.
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
try {
Thread.sleep(10000);
} catch(InterruptedException e) {
/* ignored */
}
}
}
Run Code Online (Sandbox Code Playgroud)
top
当我运行那个小程序时,这是什么意思:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
18764 myuser 20 0 10.2g 20m 8128 S 1.7 0.1 0:00.05 java
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么会这样?
uname -a说:
Linux m4fxhpsrm1dg 2.6.32-358.18.1.el6.x86_64 #1 SMP Fri Aug 2 17:04:38 EDT 2013 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
在较旧的32bit-linux机器上,同一程序仅消耗大约1G的virt.旧机器有4GB RAM,新机器有32GB.
Mic*_*rdt 86
初始堆和最大堆的默认大小定义为机器物理内存的百分比,现在生产服务器往往有很多.
您可以通过-Xms和-Xmx命令行选项进行选择.
Lua*_*aan 46
虚拟内存对你来说无关紧要.
32位和64位之间的基本区别在于64位的地址空间非常大.如果10 GiB看起来很多,请注意64位上的.NET可以像这样使用内存的TiB.然而在32位上,.NET更加保守(JVM也是如此) - 地址空间总共为4 GiB - 这并不是很多.
但这无关紧要 - 没关系.这只是一个大大简化编程的事情,并且对主机操作系统没有任何负面影响.它为VM创建了一个连续的地址空间,这意味着你不必分割堆(或者更糟的是,堆栈,它或多或少是不可能的 - 但那些往往只是MiB左右)如你需要更多的"真实"记忆.当你最终提交虚拟内存时,它会变得更加真实 - 在这一点上,它或多或少必须由某些数据存储支持- 无论是页面(交换)文件还是物理RAM.
关键是,内存的物理位置不一定是连续的,但这是在您的范围之外完成的,并且映射通常非常快.另一方面,必须索引一个数组,实际上是在10个不同的虚拟地址内存块上进行分段,这是(完全不必要的)工作.
所以你有它 - 虚拟内存在64位几乎是免费的.基本方法是"如果它在那里,使用它".你不是限制其他应用程序,它可以节省你相当多的工作,如果你做最后实际使用它.但在此之前,您只能预订.它根本不会转换为任何物理内存.你不支付今晚可能会来的朋友并坐在你的餐桌旁,但如果他们确实来了,你仍然有空间让他们坐下 - 只有当他们最终来的时候,你才真正得到"收费".
有关Java在不同计算机上以及不同版本上的行为方式的详细信息,请参阅此问题:来自Java SE 6的Sun JVM的默认最大堆大小是多少? 最大堆大小也决定了保留的虚拟内存量,因为堆必须是连续的地址空间.如果它没有预先保留,则可能发生堆无法扩展到此最大值,因为其他人在堆必须扩展的位置保留了一个地址空间区域.
这不是你的程序耗尽内存,而是Java VM保留内存,无论加载哪个程序.
事实证明,在使用虚拟内存寻址的现代计算机体系结构中(应用程序看到的"内存空间"实际上与实际物理分配的内存无关),这个虚拟"内存空间"的数量无关紧要"在启动时给予申请.这并不意味着系统已分配了这么多内存.
如果一个应用程序看到10GB的虚拟地址空间大,它向应用程序发出的信号是,如果需要,它可以使用高达10GB的内存地址.但是,在实际写入内存之前,内存实际上并未在物理RAM中分配,这是在逐页的基础上完成的,其中页面是4kB的内存部分.虚拟地址空间就是这样 - 在实际使用之前完全虚拟化.
假设一个应用程序有10GB的地址空间,它开始使用其中一些.作为一个"新鲜" - 以前未触及 - 首先写入此虚拟内存的页面,系统将在低级别上将此虚拟页面"映射"到一部分物理内存,然后编写它.但是,该应用程序本身不必担心这些细节,它只是表现为可以完全访问虚拟的内存区域.
对于Java应用程序,它不是应用程序本身,而是分配了地址空间的Java,而Java默认只是请求一个巨大的地址空间 - 它请求的数量是相对于物理内存大小计算的,但不是因为它有任何需要保守的东西,但仅仅是为了实用性 - 一个应用程序可能不会想要足够的堆大小来完全使服务器瘫痪,所以它的运行假设不会.正如我上面所说,这并不意味着这么多是"分配"的,或者系统不得不花费很多资源这样做.
归档时间: |
|
查看次数: |
9597 次 |
最近记录: |