0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

阿里:每天100w次登陸請求, 8G內存該如何設置JVM參數(shù)?

jf_ro2CN3Fa ? 來源:千淘萬漉 ? 2023-03-13 09:44 ? 次閱讀

每天100w次登陸請求, 8G 內存該如何設置JVM參數(shù)?

    • Step1:新系統(tǒng)上線如何規(guī)劃容量?
    • Step2:該如何進行垃圾回收器的選擇?
    • Step3:如何對各個分區(qū)的比例、大小進行規(guī)劃
    • step4:棧內存大小多少比較合適?
    • step5:對象年齡應該為多少才移動到老年代比較合適?
    • step6:多大的對象,可以直接到老年代比較合適?
    • step7:垃圾回收器CMS老年代的參數(shù)優(yōu)化
    • step8:配置OOM時候的內存dump文件和GC日志
    • 調優(yōu)總結
  • 什么是ZGC?
  • 如何選擇垃圾收集器?
  • Hotspot為什么使用元空間替換了永久代?
  • 什么是Stop The World ? 什么是OopMap?什么是安全點?
d29eff8c-c02f-11ed-bfe3-dac502259ad0.jpg

在阿里云技術面終面的時候被問到這么一個問題:假設一個每天100w次登陸請求的平臺,一個服務節(jié)點 8G 內存,該如何設置JVM參數(shù)?

下面以面試題的形式給大家梳理出來,做到一箭雙雕:

  • 既供大家實操參考
  • 又供大家面試參考

大家要學習的,除了 JVM 配置方案 之外,是其 分析問題的思路、思考問題的視角。這些思路和視角,能幫助大家走更遠、更遠。

接下來,進入正題。

每天100w次登陸請求, 8G 內存該如何設置JVM參數(shù)?

每天100w次登陸請求, 8G 內存該如何設置JVM參數(shù),大概可以分為以下8個步驟 。

Step1:新系統(tǒng)上線如何規(guī)劃容量?

1.套路總結

任何新的業(yè)務系統(tǒng)在上線以前都需要去估算服務器配置和JVM的內存參數(shù),這個容量與資源規(guī)劃并不僅僅是系統(tǒng)架構師的隨意估算的,需要根據(jù)系統(tǒng)所在業(yè)務場景去估算,推斷出來一個系統(tǒng)運行模型,評估JVM性能和GC頻率等等指標。以下是我結合大牛經驗以及自身實踐來總結出來的一個建模步驟:

  • 計算業(yè)務系統(tǒng)每秒鐘創(chuàng)建的對象會佔用多大的內存空間,然后計算集群下的每個系統(tǒng)每秒的內存佔用空間(對象創(chuàng)建速度)
  • 設置一個機器配置,估算新生代的空間,比較不同新生代大小之下,多久觸發(fā)一次MinorGC。
  • 為了避免頻繁GC,就可以重新估算需要多少機器配置,部署多少臺機器,給JVM多大內存空間,新生代多大空間。
  • 根據(jù)這套配置,基本可以推算出整個系統(tǒng)的運行模型,每秒創(chuàng)建多少對象,1s以后成為垃圾,系統(tǒng)運行多久新生代會觸發(fā)一次GC,頻率多高。

2.套路實戰(zhàn)——以登錄系統(tǒng)為例

有些同學看到這些步驟還是發(fā)憷,說的好像是那么回事,一到實際項目中到底怎麼做我還是不知道!

光說不練假把式,以登錄系統(tǒng)為例模擬一下推演過程:

  • 假設每天100w次登陸請求,登陸峰值在早上,預估峰值時期每秒100次登陸請求。
  • 假設部署3臺服務器,每臺機器每秒處理30次登陸請求,假設一個登陸請求需要處理1秒鐘,JVM新生代里每秒就要生成30個登陸對象,1s之后請求完畢這些對象成為了垃圾。
  • 一個登陸請求對象假設20個字段,一個對象估算500字節(jié),30個登陸佔用大約15kb,考慮到RPC和DB操作,網絡通信、寫庫、寫緩存一頓操作下來,可以擴大到20-50倍,大約1s產生幾百k-1M數(shù)據(jù)。
  • 假設2C4G機器部署,分配2G堆內存,新生代則只有幾百M,按照1s1M的垃圾產生速度,幾百秒就會觸發(fā)一次MinorGC了。
  • 假設4C8G機器部署,分配4G堆內存,新生代分配2G,如此需要幾個小時才會觸發(fā)一次MinorGC。

所以,可以粗略的推斷出來一個每天100w次請求的登錄系統(tǒng),按照4C8G的3實例集群配置,分配4G堆內存、2G新生代的JVM,可以保障系統(tǒng)的一個正常負載。

基本上把一個新系統(tǒng)的資源評估了出來,所以搭建新系統(tǒng)要每個實例需要多少容量多少配置,集群配置多少個實例等等這些,并不是拍拍腦袋和胸脯就可以決定的下來的。

Step2:該如何進行垃圾回收器的選擇?

吞吐量還是響應時間

首先引入兩個概念:吞吐量和低延遲

吞吐量 = CPU在用戶應用程序運行的時間 / (CPU在用戶應用程序運行的時間 + CPU垃圾回收的時間)

響應時間 = 平均每次的GC的耗時

通常,吞吐優(yōu)先還是響應優(yōu)先這個在JVM中是一個兩難之選。

堆內存增大,gc一次能處理的數(shù)量變大,吞吐量大;但是gc一次的時間會變長,導致后面排隊的線程等待時間變長;相反,如果堆內存小,gc一次時間短,排隊等待的線程等待時間變短,延遲減少,但一次請求的數(shù)量變小(并不絕對符合)。

無法同時兼顧,是吞吐優(yōu)先還是響應優(yōu)先,這是一個需要權衡的問題。

垃圾回收器設計上的考量

  • JVM在GC時不允許一邊垃圾回收,一邊還創(chuàng)建新對象(就像不能一邊打掃衛(wèi)生,還在一邊扔垃圾)。
  • JVM需要一段Stop the world的暫停時間,而STW會造成系統(tǒng)短暫停頓不能處理任何請求;
  • 新生代收集頻率高,性能優(yōu)先,常用復制算法;老年代頻次低,空間敏感,避免復制方式。
  • 所有垃圾回收器的涉及目標都是要讓GC頻率更少,時間更短,減少GC對系統(tǒng)影響!

CMS和G1

目前主流的垃圾回收器配置是新生代采用ParNew,老年代采用CMS組合的方式,或者是完全采用G1回收器,

從未來的趨勢來看,G1是官方維護和更為推崇的垃圾回收器。

d2b1306c-c02f-11ed-bfe3-dac502259ad0.jpg

業(yè)務系統(tǒng):

  • 延遲敏感的推薦CMS;
  • 大內存服務,要求高吞吐的,采用G1回收器!

CMS垃圾回收器的工作機制

CMS主要是針對老年代的回收器,老年代是標記-清除,默認會在一次FullGC算法后做整理算法,清理內存碎片。

CMS GC 描述 Stop the world 速度
1.開始標記 初始標記僅標記GCRoots能直接關聯(lián)到的對象,速度很快 Yes 很快
2.并發(fā)標記 并發(fā)標記階段就是進行GCRoots Tracing的過程 No
3.重新標記 重新標記階段則是為了修正并發(fā)標記期間因用戶程序繼續(xù)運作而導致標記產生變動的那一部分對象的標記記錄。 Yes 很快
4.垃圾回收 并發(fā)清理垃圾對象(標記清除算法) No
  • 優(yōu)點:并發(fā)收集、主打“低延時” 。在最耗時的兩個階段都沒有發(fā)生STW,而需要STW的階段都以很快速度完成。
  • 缺點:1、消耗CPU;2、浮動垃圾;3、內存碎片
  • 適用場景:重視服務器響應速度,要求系統(tǒng)停頓時間最短。

總之:

業(yè)務系統(tǒng),延遲敏感的推薦CMS;

大內存服務,要求高吞吐的,采用G1回收器!

Step3:如何對各個分區(qū)的比例、大小進行規(guī)劃

一般的思路為:

首先,JVM最重要最核心的參數(shù)是去評估內存和分配,第一步需要指定堆內存的大小,這個是系統(tǒng)上線必須要做的,-Xms 初始堆大小,-Xmx 最大堆大小,后臺Java服務中一般都指定為系統(tǒng)內存的一半,過大會佔用服務器的系統(tǒng)資源,過小則無法發(fā)揮JVM的最佳性能。

其次,需要指定-Xmn新生代的大小,這個參數(shù)非常關鍵,靈活度很大,雖然sun官方推薦為3/8大小,但是要根據(jù)業(yè)務場景來定,針對于無狀態(tài)或者輕狀態(tài)服務(現(xiàn)在最常見的業(yè)務系統(tǒng)如Web應用)來說,一般新生代甚至可以給到堆內存的3/4大?。魂P注公z號:碼猿技術專欄,回復關鍵詞:1111 獲取阿里內部java性能調優(yōu)手冊!而對于有狀態(tài)服務(常見如IM服務、網關接入層等系統(tǒng))新生代可以按照默認比例1/3來設置。服務有狀態(tài),則意味著會有更多的本地緩存和會話狀態(tài)信息常駐內存,應為要給老年代設置更大的空間來存放這些對象。

最后,是設置-Xss棧內存大小,設置單個線程棧大小,默認值和JDK版本、系統(tǒng)有關,一般默認512~1024kb。一個后臺服務如果常駐線程有幾百個,那麼棧內存這邊也會佔用了幾百M的大小。

JVM參數(shù) 描述 默認 推薦
-Xms Java堆內存的大小 OS內存64/1 OS內存一半
-Xmx Java堆內存的最大大小 OS內存4/1 OS內存一半
-Xmn Java堆內存中的新生代大小,扣除新生代剩下的就是老年代的內存大小了 跌認堆的1/3 sun推薦3/8
-Xss 每個線程的棧內存大小 和idk有關 sun

對于8G內存,一般分配一半的最大內存就可以了,因為機器本上還要占用一定內存,一般是分配4G內存給JVM,

引入性能壓測環(huán)節(jié),測試同學對登錄接口壓至1s內60M的對象生成速度,采用ParNew+CMS的組合回收器,

正常的JVM參數(shù)配置如下:

-Xms3072M-Xmx3072M-Xss1M-XX:MetaspaceSize=256M-XX:MaxMetaspaceSize=256M-XX:SurvivorRatio=8

這樣設置可能會由于動態(tài)對象年齡判斷原則 導致頻繁full gc。為啥呢?

壓測過程中,短時間(比如20S后)Eden區(qū)就滿了,此時再運行的時候對象已經無法分配,會觸發(fā)MinorGC,

假設在這次GC后S1裝入100M,馬上過20S又會觸發(fā)一次MinorGC,多出來的100M存活對象+S1區(qū)的100M已經無法順利放入到S2區(qū),此時就會觸發(fā)JVM的動態(tài)年齡機制,將一批100M左右的對象推到老年代保存,持續(xù)運行一段時間,系統(tǒng)可能一個小時候內就會觸發(fā)一次FullGC。

按照默認81的比例來分配時, survivor區(qū)只有 1G的 10%左右,也就是幾十到100M,

如果 每次minor GC垃圾回收過后進入survivor對象很多,并且survivor對象大小很快超過 Survivor 的 50% , 那么會觸發(fā)動態(tài)年齡判定規(guī)則,讓部分對象進入老年代.

而一個GC過程中,可能部分WEB請求未處理完畢, 幾十兆對象,進入survivor的概率,是非常大的,甚至是一定會發(fā)生的.

如何解決這個問題呢?為了讓對象盡可能的在新生代的eden區(qū)和survivor區(qū), 盡可能的讓survivor區(qū)內存多一點,達到200兆左右,

于是我們可以更新下JVM參數(shù)設置:

-Xms3072M-Xmx3072M-Xmn2048M-Xss1M-XX:MetaspaceSize=256M-XX:MaxMetaspaceSize=256M-XX:SurvivorRatio=8

說明:
‐Xmn2048M‐XX:SurvivorRatio=8
年輕代大小2g,eden與survivor的比例為8:1:1,也就是1.6g:0.2g:0.2g
d2ca57b8-c02f-11ed-bfe3-dac502259ad0.jpg

survivor達到200m,如果幾十兆對象到底survivor, survivor 也不一定超過 50%

這樣可以防止每次垃圾回收過后,survivor對象太早超過 50% ,

這樣就降低了因為對象動態(tài)年齡判斷原則導致的對象頻繁進入老年代的問題,

什么是JVM動態(tài)年齡判斷規(guī)則呢?

對象進入老年代的動態(tài)年齡判斷規(guī)則 (動態(tài)晉升年齡計算閾值):Minor GC 時,Survivor 中年齡 1 到 N 的對象大小超過 Survivor 的 50% 時,則將大于等于年齡 N 的對象放入老年代。

核心的優(yōu)化策略是:是讓短期存活的對象盡量都留在survivor里,不要進入老年代,這樣在minor gc的時候這些對象都會被回收,不會進到老年代從而導致full gc 。

應該如何去評估新生代內存和分配合適?

這里特別說一下,JVM最重要最核心的參數(shù)是去評估內存和分配,

第一步需要指定堆內存的大小,這個是系統(tǒng)上線必須要做的,-Xms 初始堆大小,-Xmx 最大堆大小,

后臺Java服務中一般都指定為系統(tǒng)內存的一半,過大會佔用服務器的系統(tǒng)資源,過小則無法發(fā)揮JVM的最佳性能。

其次需要指定-Xmn新生代的大小,這個參數(shù)非常關鍵,靈活度很大,雖然sun官方推薦為3/8大小,但是要根據(jù)業(yè)務場景來定:

  • 針對于無狀態(tài)或者輕狀態(tài)服務(現(xiàn)在最常見的業(yè)務系統(tǒng)如Web應用)來說,一般新生代甚至可以給到堆內存的3/4大?。?/li>
  • 而對于有狀態(tài)服務(常見如IM服務、網關接入層等系統(tǒng))新生代可以按照默認比例1/3來設置。

服務有狀態(tài),則意味著會有更多的本地緩存和會話狀態(tài)信息常駐內存,應為要給老年代設置更大的空間來存放這些對象。

step4:棧內存大小多少比較合適?

-Xss棧內存大小,設置單個線程棧大小,默認值和JDK版本、系統(tǒng)有關,一般默認512~1024kb。一個后臺服務如果常駐線程有幾百個,那麼棧內存這邊也會佔用了幾百M的大小。

step5:對象年齡應該為多少才移動到老年代比較合適?

假設一次minor gc要間隔二三十秒,并且,大多數(shù)對象一般在幾秒內就會變?yōu)槔?/p>

如果對象這么長時間都沒被回收,比如2分鐘沒有回收,可以認為這些對象是會存活的比較長的對象,從而移動到老年代,而不是繼續(xù)一直占用survivor區(qū)空間。

所以,可以將默認的15歲改小一點,比如改為5,

那么意味著對象要經過5次minor gc才會進入老年代,整個時間也有一兩分鐘了(5*30s= 150s),和幾秒的時間相比,對象已經存活了足夠長時間了。

所以:可以適當調整JVM參數(shù)如下:

‐Xms3072M‐Xmx3072M‐Xmn2048M‐Xss1M‐XX:MetaspaceSize=256M‐XX:MaxMetaspaceSize=256M‐XX:SurvivorRatio=8‐XX:MaxTenuringThreshold=5

step6:多大的對象,可以直接到老年代比較合適?

對于多大的對象直接進入老年代(參數(shù)-XX:PretenureSizeThreshold),一般可以結合自己系統(tǒng)看下有沒有什么大對象 生成,預估下大對象的大小,一般來說設置為1M就差不多了,很少有超過1M的大對象,

所以:可以適當調整JVM參數(shù)如下:

‐Xms3072M‐Xmx3072M‐Xmn2048M‐Xss1M‐XX:MetaspaceSize=256M‐XX:MaxMetaspaceSize=256M‐XX:SurvivorRatio=8‐XX:MaxTenuringThreshold=5‐XX:PretenureSizeThreshold=1M

step7:垃圾回收器CMS老年代的參數(shù)優(yōu)化

JDK8默認的垃圾回收器是-XX:+UseParallelGC(年輕代)和-XX:+UseParallelOldGC(老年代),

如果內存較大(超過4個G,只是經驗 值),還是建議使用G1.

這里是4G以內,又是主打“低延時” 的業(yè)務系統(tǒng),可以使用下面的組合:

ParNew+CMS(-XX:+UseParNewGC-XX:+UseConcMarkSweepGC)

新生代的采用ParNew回收器,工作流程就是經典復制算法,在三塊區(qū)中進行流轉回收,只不過采用多線程并行的方式加快了MinorGC速度。

老生代的采用CMS。再去優(yōu)化老年代參數(shù) :比如老年代默認在標記清除以后會做整理,還可以在CMS的增加GC頻次還是增加GC時長上做些取舍,

如下是響應優(yōu)先的參數(shù)調優(yōu):

XX:CMSInitiatingOccupancyFraction=70

設定CMS在對內存占用率達到70%的時候開始GC(因為CMS會有浮動垃圾,所以一般都較早啟動GC)

XX:+UseCMSInitiatinpOccupancyOnly

和上面搭配使用,否則只生效一次

-XX:+AlwaysPreTouch

強制操作系統(tǒng)把內存真正分配給IVM,而不是用時才分配。

綜上,只要年輕代參數(shù)設置合理,老年代CMS的參數(shù)設置基本都可以用默認值,如下所示:

‐Xms3072M‐Xmx3072M‐Xmn2048M‐Xss1M‐XX:MetaspaceSize=256M‐XX:MaxMetaspaceSize=256M‐XX:SurvivorRatio=8‐XX:MaxTenuringThreshold=5‐XX:PretenureSizeThreshold=1M‐XX:+UseParNewGC‐XX:+UseConcMarkSweepGC‐XX:CMSInitiatingOccupancyFraction=70‐XX:+UseCMSInitiatingOccupancyOnly‐XX:+AlwaysPreTouch

參數(shù)解釋

1.‐Xms3072M ‐Xmx3072M 最小最大堆設置為3g,最大最小設置為一致防止內存抖動

2.‐Xss1M 線程棧1m

3.‐Xmn2048M ‐XX:SurvivorRatio=8 年輕代大小2g,eden與survivor的比例為81,也就是1.6g0.2g

4.-XX:MaxTenuringThreshold=5 年齡為5進入老年代 5.‐XX:PretenureSizeThreshold=1M 大于1m的大對象直接在老年代生成

6.‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC 使用ParNew+cms垃圾回收器組合

7.‐XX:CMSInitiatingOccupancyFraction=70 老年代中對象達到這個比例后觸發(fā)fullgc

8.‐XX:+UseCMSInitiatinpOccupancyOnly 老年代中對象達到這個比例后觸發(fā)fullgc,每次

9.‐XX:+AlwaysPreTouch 強制操作系統(tǒng)把內存真正分配給IVM,而不是用時才分配。

step8:配置OOM時候的內存dump文件和GC日志

額外增加了GC日志打印、OOM自動dump等配置內容,幫助進行問題排查

-XX:+HeapDumpOnOutOfMemoryError

在Out Of Memory,JVM快死掉的時候,輸出Heap Dump到指定文件。

不然開發(fā)很多時候還真不知道怎么重現(xiàn)錯誤。

路徑只指向目錄,JVM會保持文件名的唯一性,叫java_pid${pid}.hprof。

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=${LOGDIR}/

因為如果指向特定的文件,而文件已存在,反而不能寫入。

輸出4G的HeapDump,會導致IO性能問題,在普通硬盤上,會造成20秒以上的硬盤IO跑滿,

需要注意一下,但在容器環(huán)境下,這個也會影響同一宿主機上的其他容器。

GC的日志的輸出也很重要:

-Xloggc:/dev/xxx/gc.log
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails

GC的日志實際上對系統(tǒng)性能影響不大,打日志對排查GC問題很重要。

一份通用的JVM參數(shù)模板

一般來說,大企業(yè)或者架構師團隊,都會為項目的業(yè)務系統(tǒng)定制一份較為通用的JVM參數(shù)模板,但是許多小企業(yè)和團隊可能就疏于這一塊的設計,如果老板某一天突然讓你負責定制一個新系統(tǒng)的JVM參數(shù),你上網去搜大量的JVM調優(yōu)文章或博客,結果發(fā)現(xiàn)都是零零散散的、不成體系的JVM參數(shù)講解,根本下不了手,這個時候你就需要一份較為通用的JVM參數(shù)模板了,不能保證性能最佳,但是至少能讓JVM這一層是穩(wěn)定可控的,

在這里給大家總結了一份模板:

基于4C8G系統(tǒng)的ParNew+CMS回收器模板(響應優(yōu)先),新生代大小根據(jù)業(yè)務靈活調整!

-Xms4g
-Xmx4g
-Xmn2g
-Xss1m
-XX:SurvivorRatio=8
-XX:MaxTenuringThreshold=10
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=70
-XX:+UseCMSInitiatingOccupancyOnly
-XX:+AlwaysPreTouch
-XX:+HeapDumpOnOutOfMemoryError
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:gc.log

如果是GC的吞吐優(yōu)先,推薦使用G1,基于8C16G系統(tǒng)的G1回收器模板:

G1收集器自身已經有一套預測和調整機制了,因此我們首先的選擇是相信它,

即調整-XX:MaxGCPauseMillis=N參數(shù),這也符合G1的目的——讓GC調優(yōu)盡量簡單!

同時也不要自己顯式設置新生代的大?。ㄓ?Xmn或-XX:NewRatio參數(shù)),

如果人為干預新生代的大小,會導致目標時間這個參數(shù)失效。

-Xms8g
-Xmx8g
-Xss1m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=150
-XX:InitiatingHeapOccupancyPercent=40
-XX:+HeapDumpOnOutOfMemoryError
-verbose:gc
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
G1參數(shù) 描述 默認值
XX:MaxGCPauseMillis=N 最大GC停頓時間。柔性目標,JVM滿足90%,不保證100%。 200
-XX:nitiatingHeapOccupancyPercent=n 當整個堆的空間使用百分比超過這個值時,就會融發(fā)MixGC 45

針對-XX:MaxGCPauseMillis來說,參數(shù)的設置帶有明顯的傾向性:調低↓:延遲更低,但MinorGC頻繁,MixGC回收老年代區(qū)減少,增大Full GC的風險。調高↑:單次回收更多的對象,但系統(tǒng)整體響應時間也會被拉長。

針對InitiatingHeapOccupancyPercent來說,調參大小的效果也不一樣:調低↓:更早觸發(fā)MixGC,浪費cpu。調高↑:堆積過多代回收region,增大FullGC的風險。

調優(yōu)總結

系統(tǒng)在上線前的綜合調優(yōu)思路:

1、業(yè)務預估:根據(jù)預期的并發(fā)量、平均每個任務的內存需求大小,然后評估需要幾臺機器來承載,每臺機器需要什么樣的配置。

2、容量預估:根據(jù)系統(tǒng)的任務處理速度,然后合理分配Eden、Surivior區(qū)大小,老年代的內存大小。

3、回收器選型:響應優(yōu)先的系統(tǒng),建議采用ParNew+CMS回收器;吞吐優(yōu)先、多核大內存(heap size≥8G)服務,建議采用G1回收器。

4、優(yōu)化思路:讓短命對象在MinorGC階段就被回收(同時回收后的存活對象

5、到目前為止,總結到的調優(yōu)的過程主要基于上線前的測試驗證階段,所以我們盡量在上線之前,就將機器的JVM參數(shù)設置到最優(yōu)!

JVM調優(yōu)只是一個手段,但并不一定所有問題都可以通過JVM進行調優(yōu)解決,大多數(shù)的Java應用不需要進行JVM優(yōu)化,我們可以遵循以下的一些原則:

  • 上線之前,應先考慮將機器的JVM參數(shù)設置到最優(yōu);
  • 減少創(chuàng)建對象的數(shù)量(代碼層面);
  • 減少使用全局變量和大對象(代碼層面);
  • 優(yōu)先架構調優(yōu)和代碼調優(yōu),JVM優(yōu)化是不得已的手段(代碼、架構層面);
  • 分析GC情況優(yōu)化代碼比優(yōu)化JVM參數(shù)更好(代碼層面);

通過以上原則,我們發(fā)現(xiàn),其實最有效的優(yōu)化手段是架構和代碼層面的優(yōu)化,而JVM優(yōu)化則是最后不得已的手段,也可以說是對服務器配置的最后一次“壓榨”。

基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

什么是ZGC?

ZGC (Z Garbage Collector)是一款由Oracle公司研發(fā)的,以低延遲為首要目標的一款垃圾收集器。

它是基于動態(tài)Region內存布局,(暫時)不設年齡分代,使用了讀屏障、染色指針和內存多重映射等技術來實現(xiàn)可并發(fā)的標記-整理算法的收集器。

在 JDK 11 新加入,還在實驗階段,

主要特點是:回收TB級內存(最大4T),停頓時間不超過10ms。

優(yōu)點:低停頓,高吞吐量, ZGC 收集過程中額外耗費的內存小

缺點:浮動垃圾

目前使用的非常少,真正普及還是需要寫時間的。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能

  • 項目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

如何選擇垃圾收集器?

在真實場景中應該如何去選擇呢,下面給出幾種建議,希望對你有幫助:

1、如果你的堆大小不是很大(比如 100MB ),選擇串行收集器一般是效率最高的。參數(shù):-XX:+UseSerialGC 。

2、如果你的應用運行在單核的機器上,或者你的虛擬機核數(shù)只有 單核,選擇串行收集器依然是合適的,這時候啟用一些并行收集器沒有任何收益。參數(shù):-XX:+UseSerialGC 。

3、如果你的應用是“吞吐量”優(yōu)先的,并且對較長時間的停頓沒有什么特別的要求。選擇并行收集器是比較好的。參數(shù):-XX:+UseParallelGC 。

4、如果你的應用對響應時間要求較高,想要較少的停頓。甚至 1 秒的停頓都會引起大量的請求失敗,那么選擇 G1 、 ZGC 、 CMS 都是合理的。雖然這些收集器的 GC 停頓通常都比較短,但它需要一些額外的資源去處理這些工作,通常吞吐量會低一些。參數(shù):-XX:+UseConcMarkSweepGC-XX:+UseG1GC 、 -XX:+UseZGC 等。從上面這些出發(fā)點來看,我們平常的 Web 服務器,都是對響應性要求非常高的。

選擇性其實就集中在 CMS、G1、ZGC 上。而對于某些定時任務,使用并行收集器,是一個比較好的選擇。

Hotspot為什么使用元空間替換了永久代?

什么是元空間?什么是永久代?為什么用元空間代替永久代?

我們先回顧一下方法區(qū) 吧,看看虛擬機運行時數(shù)據(jù)內存圖,如下:

d2dfdb9c-c02f-11ed-bfe3-dac502259ad0.jpg

方法區(qū)和堆一樣,是各個線程共享的內存區(qū)域,它用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼等數(shù)據(jù)。

什么是永久代?它和方法區(qū)有什么關系呢?

如果在HotSpot虛擬機上開發(fā)、部署,很多程序員都把方法區(qū)稱作永久代。

可以說方法區(qū)是規(guī)范,永久代是Hotspot針對該規(guī)范進行的實現(xiàn)。

在Java7及以前的版本,方法區(qū)都是永久代實現(xiàn)的。

什么是元空間?它和方法區(qū)有什么關系呢?

對于Java8,HotSpots取消了永久代,取而代之的是元空間(Metaspace)。

換句話說,就是方法區(qū)還是在的,只是實現(xiàn)變了,從永久代變?yōu)樵臻g了。

為什么使用元空間替換了永久代?

永久代的方法區(qū),和堆使用的物理內存是連續(xù)的。

d2ee07e4-c02f-11ed-bfe3-dac502259ad0.jpg

永久代 是通過以下這兩個參數(shù)配置大小的~

  • -XX:PremSize:設置永久代的初始大小
  • -XX:MaxPermSize: 設置永久代的最大值,默認是64M

對于永久代 ,如果動態(tài)生成很多class的話,就很可能出現(xiàn)java.lang.OutOfMemoryError:PermGen space錯誤 ,因為永久代空間配置有限嘛。最典型的場景是,在web開發(fā)比較多jsp頁面的時候。

JDK8之后,方法區(qū)存在于元空間(Metaspace)。

物理內存不再與堆連續(xù),而是直接存在于本地內存中,理論上機器內存有多大,元空間就有多大 。

d3049450-c02f-11ed-bfe3-dac502259ad0.jpg

可以通過以下的參數(shù)來設置元空間的大小:

  • -XX:MetaspaceSize,初始空間大小,達到該值就會觸發(fā)垃圾收集進行類型卸載,同時GC會對該值進行調整:如果釋放了大量的空間,就適當降低該值;如果釋放了很少的空間,那么在不超過MaxMetaspaceSize時,適當提高該值。
  • -XX:MaxMetaspaceSize,最大空間,默認是沒有限制的。
  • -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空間容量的百分比,減少為分配空間所導致的垃圾收集
  • -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空間容量的百分比,減少為釋放空間所導致的垃圾收集

所以,為什么使用元空間替換永久代?

表面上看是為了避免OOM異常。

因為通常使用PermSize和MaxPermSize設置永久代的大小就決定了永久代的上限,但是不是總能知道應該設置為多大合適, 如果使用默認值很容易遇到OOM錯誤。

當使用元空間時,可以加載多少類的元數(shù)據(jù)就不再由MaxPermSize控制, 而由系統(tǒng)的實際可用空間來控制啦。

什么是Stop The World ? 什么是OopMap?什么是安全點?

進行垃圾回收的過程中,會涉及對象的移動。

為了保證對象引用更新的正確性,必須暫停所有的用戶線程,像這樣的停頓,虛擬機設計者形象描述為Stop The World 。也簡稱為STW。

在HotSpot中,有個數(shù)據(jù)結構(映射表)稱為OopMap

一旦類加載動作完成的時候,HotSpot就會把對象內什么偏移量上是什么類型的數(shù)據(jù)計算出來,記錄到OopMap。

在即時編譯過程中,也會在特定的位置 生成 OopMap,記錄下棧上和寄存器里哪些位置是引用。

這些特定的位置主要在:

1.循環(huán)的末尾(非 counted 循環(huán))

2.方法臨返回前 / 調用方法的call指令后

3.可能拋異常的位置

這些位置就叫作安全點(safepoint)。

用戶程序執(zhí)行時并非在代碼指令流的任意位置都能夠在停頓下來開始垃圾收集,而是必須是執(zhí)行到安全點才能夠暫停。

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    2978

    瀏覽量

    73817
  • JVM
    JVM
    +關注

    關注

    0

    文章

    157

    瀏覽量

    12197
  • 收集器
    +關注

    關注

    0

    文章

    30

    瀏覽量

    3120

原文標題:阿里:每天100w次登陸請求, 8G 內存該如何設置JVM參數(shù)?

文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    容器JVM內存配置最佳實踐

    Killer)機制,此時系統(tǒng)會終止內存占用較多的進程以保證系統(tǒng)的正常運行。特別是在容器環(huán)境下,不合理的JVM參數(shù)設置會導致各種異?,F(xiàn)象產生,例如應用堆大小還未到達JVM
    發(fā)表于 06-20 09:45 ?851次閱讀
    容器<b class='flag-5'>JVM</b><b class='flag-5'>內存</b>配置最佳實踐

    我想請問下 手機可以登陸 網站嗎

    我想請問下 手機可以登陸 網站嗎、我用手機找到論壇了 但是登陸時出現(xiàn)的問題
    發(fā)表于 05-28 20:14

    100W擴音機電路

    100W擴音機電路
    發(fā)表于 10-19 14:27 ?5730次閱讀

    100W逆變電源電路

    100W逆變電源電路原理圖
    發(fā)表于 11-03 19:18 ?1590次閱讀
    <b class='flag-5'>100W</b>逆變電源電路

    100W RMS的放大器電路 (100W rms ampli

    100W RMS的放大器電路 (100W rms amplifier) Circuit Description: This is a 100 watt basic power amp that was designed t
    發(fā)表于 12-23 18:04 ?3278次閱讀
    <b class='flag-5'>100W</b> RMS的放大器電路 (<b class='flag-5'>100W</b> rms ampli

    傳iPhone8將一破保守的傳統(tǒng)采用8G超速內存?

    隨著6G內存智能手機在市場上廣泛出現(xiàn),今年我們將更加普遍地看到8G內存的智能設備。據(jù)最新消息,三星Galaxy S8 將是首個采用
    發(fā)表于 01-13 09:08 ?944次閱讀

    Fitomodule 100W項目開源

    電子發(fā)燒友網站提供《Fitomodule 100W項目開源.zip》資料免費下載
    發(fā)表于 08-22 16:14 ?14次下載
    Fitomodule <b class='flag-5'>100W</b>項目開源

    在4G內存的機器上,申請8G內存會怎么樣?

    這篇文章其實之前發(fā)過,但是最近有位讀者跟我反饋,我文章中的實驗在 64 位操作系統(tǒng)、2 G 物理內存的場景,申請 8G 內存是沒問題的,而他也是這個環(huán)境,為什么他就無法申請成功呢?
    的頭像 發(fā)表于 01-31 16:41 ?865次閱讀

    jvm內存溢出如何定位解決

    在Java應用程序中,JVM(Java虛擬機)內存溢出是指Java應用程序試圖分配的內存超過了JVM所允許的最大內存大小,導致程序無法正常執(zhí)
    的頭像 發(fā)表于 12-05 11:05 ?1271次閱讀

    jvm調優(yōu)參數(shù)

    和類元數(shù)據(jù)等方面的參數(shù)設置。下面我們將詳細介紹這些參數(shù)以及如何進行優(yōu)化。 首先,堆內存JVM中用于存放對象實例的內存區(qū)域。通過調整堆
    的頭像 發(fā)表于 12-05 11:29 ?585次閱讀

    jvm參數(shù)設置jvm調優(yōu)

    JVM(Java虛擬機)參數(shù)設置和調優(yōu)對于提高Java應用程序的性能和穩(wěn)定性非常重要。在本文中,我們將詳細介紹JVM參數(shù)
    的頭像 發(fā)表于 12-05 11:36 ?1359次閱讀

    jvm配置metaspace最大值的參數(shù)

    內存限制):參數(shù)用于設置JVM堆的最大大小。在JVM啟動時,可以使用以下命令來配置Metas
    的頭像 發(fā)表于 12-05 14:21 ?1919次閱讀

    weblogic jvm參數(shù)配置

    ,讓我們來了解一些常用的JVM參數(shù): -Xms 和 -Xmx參數(shù):這些參數(shù)分別用于設置Java虛擬機的初始堆大小和最大堆大小。-Xms
    的頭像 發(fā)表于 12-05 14:31 ?1310次閱讀

    weblogic設置jvm內存大小

    WebLogic是一種Java EE應用服務器,用于構建和部署企業(yè)級Java應用程序。在配置WebLogic服務器時,設置JVM內存大小非常重要,這可以提高應用程序的性能和可靠性。本文將詳細介紹
    的頭像 發(fā)表于 12-05 14:44 ?2871次閱讀

    eclipse設置jvm內存大小

    Eclipse是一個功能強大的集成開發(fā)環(huán)境(IDE),常用于Java開發(fā)。為了保證Eclipse的性能和穩(wěn)定性,我們可以根據(jù)需要來設置JVM內存大小。本文將詳細介紹如何在Eclipse中設置
    的頭像 發(fā)表于 12-06 11:43 ?1788次閱讀