最近在开发Java的程序。本来我是一直很喜欢Java的内存管理的,不需要担心分配内存,只管分配,垃圾收集器自己会给你回收内存的。现在开发的程序数据量很大,为了速度快,我准备把所有的信息加载进内存,这样可以保证快速响应。我还在反复算内存,想想自己的数据量,现在刚开始的时候应该够了(我的机器是4G内存,虽然Windows就认3.5G,但是比起我现在的数据量应该没问题)。
没想到第一个实验的程序,跑了几个小时,就遇到了Out of Memory Exception了。看看自己的虚拟机设置,我设置的是-Xms512M
-Xmx1024M。想都没想,直接改成-Xms512M -Xmx2048M,结果直接就Could not reserve enough space for
object heap。程序都起不来了。这才发现原来最大内存还有限制。上网搜了一下,发现很多讨论这个问题的文章。最终在BEA的DEV2DEV论坛发现了最有用的
一篇
这里的版主YuLimin 做了测试,得出结论:
公司
JVM版本
最大内存(兆)client 最大内存(兆)server
SUN
1.5.x
1492
1520
SUN
1.5.5(Linux)
2634
2660
SUN
1.4.2
1564
1564
SUN
1.4.2(Linux)
1900
1260
IBM
1.4.2(Linux)
2047
N/A
BEA JRockit 1.5 (U3)
1909
1902
我现在用的是JDK1.6. 0_05,测试了一下。在Client状态下最大是,我的JDK不认-Server参数,测试不了Server状态。估计差不多。
SUN
1.6.0
1442
N/a
看样子用Java想用大内存也是不可能的了。而且一般的说法是内存太大了,垃圾收集的时间就会长。这也可以理解,一般是内存不够用了才收集的,扫描2G内存比1G当然要慢多了,而且内存对象多了,估计关系是指数上升的。
下面附上YuLimin的测试方法和测试记录。
测试方法:在命令行下用 java -XmxXXXXM -version
命令来进行测试,然后逐渐的增大XXXX的值,如果执行正常就表示指定的内存大小可用,否则会打印错误信息。
- 堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java
虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java
虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap
memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给
自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法
的代码都在非堆内存中。 - 堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由
-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆
直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。 - 非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。 - JVM内存限制(最大值)
首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限
大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是
2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。所以说设置VM参数导致程序无法启动主要有以下几种原因:
1) 参数中-Xms的值大于-Xmx,或者-XX:PermSize的值大于-XX:MaxPermSize;
2)
-Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制,比如当前操作系统最大内存限制,或者实际的物理内存等等。说到实际物理
内存这里需要说明一点的是,如果你的内存是1024MB,但实际系统中用到的并不可能是1024MB,因为有一部分被硬件占用了。
Java虚拟机支持的最大内存限制,码迷,mamicode.com