最近在开发的程序。本来我是一直很喜欢的内存管理的,不需要担心分配内存,只管分配,垃圾收集器自己会给你回收内存的。现在开发的程序数据量很大,为了速度快,我准备把所有的信息加载进内存,这样可以保证快速响应。我还在反复算内存,想想自己的数据量,现在刚开始的时候应该够了(我的机器是4g内存,虽然就认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
1.5.5(linux)
2634
2660
1.4.2
1564
1564
1.4.2(linux)
1900
1260
ibm
2047
n/a
bea jrockit 1.5 (u3)
1909
1902
我现在用的是jdk1.6. 0_05,了一下。在client状态下最大是,我的jdk不认-server参数,测试不了server状态。估计差不多。
1.6.0
1442
看样子用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,因为有一部分被硬件占用了。