[资料] 关于XMS 和XMX参数问题求教

jjshanwei 2012-01-11
-Xms4096m -Xmx4096m 我的一个Java应用里这这样配置的,按一般资料里都说堆最大值和最小值设为一样是为了避免多次内存分配的开销,

但在我实际的应用中应用刚起来时 没占用了4096m内存?,而是随着系统运行逐渐增长到4g的,这是为什么呢?  求解惑!
RednaxelaFX 2012-01-11
或者你试试加上 -XX:+AlwaysPreTouch 看看行为有没有变化?
jjshanwei 2012-01-11
RednaxelaFX:

如你所言,加上-XX:+AlwaysPreTouch 后,在应用启动后内存占用确实立即上升到最大值?
这是为什么呢?

另外,加上此参数后随后我shutdown应用报:
Error occurred during initialization of VM
Could not reserve enough space for object heap

导致jvm不能正常关闭。
RednaxelaFX 2012-01-11
jjshanwei 写道
另外,加上此参数后随后我shutdown应用报:
Error occurred during initialization of VM
Could not reserve enough space for object heap

导致jvm不能正常关闭。

这个案例的操作系统、JDK的具体版本分别是多少?
这个错误必然是在某个正在启动过程中的JVM报的,而不是正在关闭中的JVM。
能确认一下到底是哪个进程在报错么?以及,这个新起的Java进程是否是某个别的Java进程所启动的,例如说新起的是个子进程,而母进程也是Java写的,用ProcessBuilder活Runtime.exec()之类的来起新进程?
jjshanwei 2012-01-11
jdk的版本:
1.6.0_22
操作系统:
CentOS release 5.5 (Final) 内核:2.6.18

启动的其实就是一个tomcate,用的是tomcat本身的startup.sh,关闭时用的是tomcate的shutdonw.sh命令,就会报那个错,会导致关不了,不是用在一个java进程里去启动另一个java进程。

jjshanwei 2012-01-11
这是详细jvm参数配置:
-server -Xms1g -Xmx1g -XX:+AlwaysPreTouch -XX:NewSize=384m -XX:MaxNewSize=384m -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=8 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:MaxTenuringThreshold=8 -XX:+UseCompressedOops -XX:+DisableExplicitGC -Xnoclassgc -XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled -XX:+CMSParallelRemarkEnabled -XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=75 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:-UseAdaptiveSizePolicy -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -Xloggc:/opt/tomcat7_leaguelib-web/logs/gc.log -verbose:gc
RednaxelaFX 2012-01-11
报错的是shutdown.sh的那个吧…这就说得通了。
Tomcat的shutdown.sh是起一个新的Java进程,向正在运行的Tomcat发消息让它关闭。现在你遇到的是shutdown.sh要启动的新Java进程无法申请到足够大的GC heap空间。

你用的是32位系统还是64位?物理内存有多少?同一台机器上跑了些啥服务?
jjshanwei 2012-01-12
嗯,今天再测试确实可以正常关闭,但关闭时间却比不启用该参数是要长。
这台机器确实还有其他的应用在跑,昨天没留意物理内存情况。
谢谢你!
AlwaysPreTouch,这个参数有哪些作用,能在生产环境启用他吗?
RednaxelaFX 2012-01-12
AlwaysPreTouch就是让HotSpot VM在commit内存时跑个循环来强制保证申请的内存真的commit了。

引用自Sun JDK 6里的HotSpot VM代码:

VirtualSpace:
  if (pre_touch || AlwaysPreTouch) {
    int vm_ps = os::vm_page_size();
    for (char* curr = previous_high;
         curr < unaligned_new_high;
         curr += vm_ps) {
      // Note the use of a write here; originally we tried just a read, but
      // since the value read was unused, the optimizer removed the read.
      // If we ever have a concurrent touchahead thread, we'll want to use
      // a read, to avoid the potential of overwriting data (if a mutator
      // thread beats the touchahead thread to a page).  There are various
      // ways of making sure this read is not optimized away: for example,
      // generating the code for a read procedure at runtime.
      *curr = 0;
    }
  }

MutableSpace:
void MutableSpace::pretouch_pages(MemRegion mr) {
  for (volatile char *p = (char*)mr.start(); p < (char*)mr.end(); p += os::vm_page_size()) {
    char t = *p; *p = t;
  }
}


没啥别的特别的。它的效果就跟你最初想要的“为了避免多次内存分配的开销”一致,从虚拟内存系统的意义上说。
问题就是:一开始就commit掉这些内存是否是正确的行为。从你的描述看,你要的就是这个行为,那就用它好了,生产环境也没啥问题。用了之后留意一下page swapping有没有增加。

随便搜一下这个参数就能搜到很多讨论是跟这个参数相关的;有时候解决问题靠这个参数,有时候这个参数会造成奇怪的问题。

某些特殊的系统上不建议使用这个参数。
这些系统可能依赖于overcommit,或许会在同一台机器上启动多个Java进程,并且为每个Java进程都配置非常大的GC heap(-Xmx和-XX:MaxPermSize),实际上并没用到其reserved的极限。典型场景是Hadoop的task node。
在这种环境上如果打开AlwaysPreTouch就会让每个Java进程都真的commit了很大的内存,跟overcommit会冲突。
Global site tag (gtag.js) - Google Analytics