我们启动一个java进程,通常会设置相关的JVML参数,比如堆的内存,栈的内存,方法区(元空间)的内存,如下:
通常,如果我们用默认值,那么
-Xms
指定jvm堆的初始大小,默认为物理内存的1/64,最小为1M;可以指定单位,比如k、m,若不指定,则默认为字节。
-Xmx
指定jvm堆的最大值,默认为物理内存的1/4或者1G,最小为2M;单位与-Xms一致。
-Xmn
新生代栈堆内存的1/3
-Xss
设置单个线程栈的大小,一般默认为512k。
设置方式
比如我们微服务的启动可以用如下命令设置:
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar microservice‐eureka‐server.jar
上面的意思是设置堆的初始内存为2048M,最大内存为2048M,新生代为1024M,栈(每个线程)的内存为512k,方法区为256M,最大值也为256M
简单例子
比如我们设置了堆内存为128M,那么新生代占用2/3也就是差不多42M,如果程序一秒钟产生的对象有1M,那么在42秒左右就会触发1次minor gc,如果业务量某时刻暴增几十倍比如秒杀业务或者抽奖业务,那么一秒钟可能产生对象40M,也就是差不多一秒钟就要触发minor gc ,在十多秒就会使得对象的分代年龄到达默认值15,也就是说如过一个业务流程耗时15s(在高并发的状态下是完全有可能的),该业务产生的对象就会移动到老年代,这种业务结束后就不会引用的对象移动到老年代是对老年代资源空间的浪费,并且在老年代堆满后会触发full gc,直接stop world,对程序性能的影响较大。
所以如果你的业务量可能会到达一秒钟产生50M的对象的话,最起码要保证半分钟之内(假设业务流程可能半分钟才执行完)不会触发minor gc为好,那么30s也就是会有1500M对象,也就是要保证新生代有1500M,那么表明堆要有内存1500/(2/3)=2250M也就是差不多2G堆内存,那么除开方法区和栈等大概JVM要占用4G,那么整个服务器可能要8G才行,所以微服务项目什么的首选4核8G的服务器较为妙。