我們啟動一個java程序,通常會設定相關的JVML引數,比如堆的記憶體,棧的記憶體,方法區(元空間)的記憶體,如下:
通常,如果我們用預設值,那麼
-Xms指定jvm堆的初始大小,預設為物理記憶體的1/64,最小為1M;可以指定單位,比如k、m,若不指定,則預設為位元組。
-Xmx指定jvm堆的最大值,預設為物理記憶體的1/4或者1G,最小為2M;單位與-Xms一致。
-Xmn新生代棧堆記憶體的2/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的伺服器較為妙。