JAVA技(jì)術(shù)
  當前位置:首頁 > 技(jì)術(shù)支持 > JAVA技(jì)術(shù)
JVM--內(nèi)存參數(shù)設置及常見(jiàn)錯(cuò)誤✘¶π總結
發布時(shí)間(jiān):2017-02-06 浏$↕覽:8251次
  

一(yī)、  JVM規範

JVM規範對(duì)Java運行(xíng)時(shí)的(de)內(n☆₹èi)存劃定了(le)幾塊區(qū)域(®₩↕詳見(jiàn)這(zhè)裡(lǐ)),有(yǒu):JVM棧(Java Virtual Machine Stacks)、堆(Hea∑ p)、方法區(qū)(Method Are₹ a)、常量池(Runtime Constant P₹★ool)、本地(dì)方法棧(Native Method Stack£₹'∏s),但(dàn)對(duì)各塊區(qū)域的(de)內(nèi)存布λ'Ω局和(hé)地(dì)址空(kōng)間(jiān) β卻沒有(yǒu)明(míng)确規定,而留給各JVM廠(chǎng)商 ™發揮的(de)空(kōng)間(jiān)。

二、  HotSpot JVM

Sun自(zì)家(jiā)的(de)HotSpot JVM實現(xiàn​™☆↓)對(duì)堆內(nèi)存結構有(yǒu)相(xiàng)對(du∏φ ≥ì)明(míng)确的(de)說(shuō)明(míng)∑γ。按照(zhào)HotSpot JVM÷σ↕的(de)實現(xiàn),堆內(nèi)存分(fēn)為(wèi) ​&3個(gè)代:Young Generation、Old(Tenured→ ') Generation、Permanent Generation。衆所周知(¶Ωzhī),GC(垃圾收集)就(jiù)是(shì)​¶發生(shēng)在堆內(nèi)存這(zhè)三個(gè)代上(shàng∏ )面的(de)。Young用(yòng)于分(fδδ♣ēn)配新的(de)Java對(duì)象,&←其又(yòu)被分(fēn)為(wèi)三個(gè)部分(fēn)"§$:Eden Space和(hé)兩塊Sur☆π$ vivor Space(稱為(wèi)From和(hé $$±)To),Old用(yòng)于存放(fàng)在Gδ±≥C過程中從(cóng)Young Gen中存活下(xià)來(lái∞•)的(de)對(duì)象,Permanent用(yòng)于 ✘‌存放(fàng)JVM加載的(de)class等元數(shù)÷€據。詳情參見(jiàn)HotSpot內(nèi)存管理(lǐ)白♣<₩ (bái)皮書(shū)

     1.≠±×±Java Heap分(fēn)為(wèi)3個(gè)區(q₹​¶™ū)

      &nb™≤¥sp;  1).Young(分(fēn)為(wèi)兩個<→•‍(gè)同等大(dà)小(xiǎo)的(de)survior區(qū)和( γ£hé)一(yī)個(gè)eden區(qū),JVM默認分(fē ₩♦n)配內(nèi)存大(dà)小(xiǎo)為(wèi)survio↕™"σr:eden = 1 : 8, 可(kě)配置)

     ♠‌;    2).O™©ld(一(yī)個(gè)Old區(qū),JVM默認分(fēn)配內(>∏ nèi)存大(dà)小(xiǎo)為(wèi) Old:Young ↓ ∞&= 2:1, 可(kě)配置)

      δ★♥;   3).Permanent

     &✘±nbsp;   Young保存剛實Ω≥例化(huà)的(de)對(duì)象。當該區(qū)被填滿時 ♦↔(shí),GC會(huì)将對(duì)象↑∞移到(dào)Old區(qū)(按照(zhà←•o)一(yī)定的(de)算(suàn)法,如(rú)GC超過15次後某一(yī)對∑>∏(duì)象還(hái)存活,則會(huì)移動到(dào)O×<€÷ld區(qū),可(kě)配置)

     2.JVM有(yǒu)2個(gè)GC線程 (未查找©δβ到(dào)詳細資料)

    ₽ ;     第一(yī)個(gè)§¶☆→線程負責回收Heap的(de)Young區(qū)
    &nb€ σsp;    第二個(gè)線程在Heap不(​​♣∏bù)足時(shí),遍曆Heap,将Young 區(qū)升級為(wèi)O↔ lder區(qū)

    ¶<∞;     以下(xià)是(sh®↔↑ì)我的(de)機(jī)器(qì)的(de)執行•×₽'(xíng)該命令查看(kàn)到(dào)的(de)JVM相(xiàn♣★£g)關線程:jstack -l pid

 

  1. "VMThread" prio=10 ti ∞↕d=0x00007fa2c4061000 nγδ←"id=0x18431 runnable  ∑;  
  2. "GCtask thread#0 (Paral'πlelGC)" prio=10 tid=§πα0x00007fa2c401a000 n≈>id=0x1842frunnable  
  3. "GCtask thread#1 (Paralle₽πlGC)" prio=10 tid=0x±γ00007fa2c401b800 nid=0x18430runnab÷↕$ le  
  4. "VMPeriodic Task Th§® εread" prio=10&nbs↓•"p;tid=0x00007fa2c4097800φ₹‌ nid=0x18438 waitin<φ&'gon condition  γ☆¶ 
"VMThread" prio=10 tid=0x0 ☆÷ 0007fa2c4061000 nid=0x18431 ₹φ♣↓runnable "GCtask thread#0 (Para↑÷©<llelGC)" prio=10 tid=0x00007fa2c401a0≠♦♥00 nid=0x1842frunnable "G€₹↑Ctask thread#1 (ParallelGC)" ×Ω♣§prio=10 tid=0x00007fa2c401✔‌b800 nid=0x18430runnable "VMPeriodic T♣€©ask Thread" prio=10 tid=0x00007fa2c40 ₹97800 nid=0x18438 waitingo ¶αn condition

三、  JVM參數(shù)設置

非穩态選項使用(yòng)說(shuō)明(míng):
-XX:+<option> 啓★≥™Ω用(yòng)option
-XX:-<option> 不(bù)₹©α啓用(yòng)option
-XX:<option>=<numbe←πr> 設定option的(↓¶de)值為(wèi)數(shù)字類型,可(kě)跟單位,例如(rú)&n  bsp;32k, 1024m, 2g
-XX:<option>=&l αt;string> 設定option的(de)值為(₽¥♥±wèi)字符串,例如(rú)-XX:HeapDumpPath=./dump.cπβ•σore

性能(néng)選項

選項與默認值 默認值與限制(zhì) 描述
-Xms 初始堆大(dà)小(xiǎo) 默認(MinHeapFreeRatio參數(shù)可(kě)以→β✘調整)空(kōng)餘堆內(nèi)存小(xiǎo)于40%時(ε↕¥shí),JVM就(jiù)會(huì)增大(γ​σ↑dà)堆直到(dào)-Xmx的(de)最大(dà§÷)限制(zhì).
-Xmx 最大(dà)堆大(dà)小(xiǎo) 默認(MaxHeapFreeRatio參數(shù÷€$)可(kě)以調整)空(kōng)餘堆內(nèi)存大(dà)于α"70%時(shí),JVM會(huì)減少(s↑¥™®hǎo)堆直到(dào) -Xms的(de)最小(xiǎo)≤↓‍₽限制(zhì).
注意:此處的(de)大(dà)小(xiǎo)是(shì)(eden+ 2 s∑ε✔urvivor space).與jmap -heap中顯示的(de)δ₽New gen是(shì)不(bù)同的(de)。
整個(gè)堆大(dà)小(xiǎo)=年(nián)輕代大(dà)小(xiǎ¥§o) + 年(nián)老(lǎo)代大(dà)小(xi™•ǎo) + 持久代大(dà)小(xiǎo).
-Xmn 年(nián)輕代大(dà)小(xiǎo)(♦↑÷1.4or lator) 增大(dà)年(nián)輕代後,将會(huì±♠ ¥)減小(xiǎo)年(nián)老(lǎo)代大(dà)小(xi↓<εǎo).此值對(duì)系統性能(néng)影(yǐng)響較≥≠‌ε大(dà),Sun官方推薦配置為(wèi)整個(gè)"λ♣堆的(de)3/8
-Xss 每個(gè)線程的(de)堆棧大(dà)小(xiǎo)φδ≈ JDK5.0以後每個(gè)線程堆棧大(dà)小(x☆‌£iǎo)為(wèi)1M,以前每個(gè)線程堆棧大(dà)€÷¶小(xiǎo)為(wèi)256K.更具應用(yòng)的(de↕≈₩)線程所需內(nèi)存大(dà)小(xiǎo)進行(xín±★¶g) 調整.在相(xiàng)同物(wù)理(lǐ)內(nèi)存下(x↑♥₩βià),減小(xiǎo)這(zhè)個(gè)值<∞δ≤能(néng)生(shēng)成更多(duō)的(de)線程.但(dàn)€∑是(shì)操作(zuò)系統對(duì)一(yī)個(gè)進程內(n₹♦èi)的(de)線程數(shù)還(há$•>₽i)是(shì)有(yǒu)限制(zhì)α✔π的(de),不(bù)能(néng)無限←↓÷σ生(shēng)成,經驗值在3000~5000左右
一(yī)般小(xiǎo)的(de)應用(yòng), 如(rú)果棧不(b€ε$ù)是(shì)很(hěn)深, 應該是(shì)128k夠用(yòng)的®ε≥(de) 大(dà)的(de)應用(yòng)↕€"★建議(yì)使用(yòng)256k。這(z≥×♠♦hè)個(gè)選項對(duì)性能(néng)影(yǐng)響♥§δα比較大(dà),需要(yào)嚴格的(de)測試。(校(xià≈✔o)長(cháng))
和(hé)threadstacksize選項解釋很(hěn)類似,官方文(γ↓​wén)檔似乎沒有(yǒu)解釋,在論壇中有(yǒu)這(zhè)ε☆↑樣一(yī)句話(huà):"”
-Xss is translated in a VM•÷♦< flag named ThreadStackSize”
一(yī)般設置這(zhè)個(gè)值就(jiù)可(kě)以了(l£<★&e)。
-XX:MaxTenuringThreshold 垃圾最大(dà)年(nián)齡 如(rú)果設置為(wèi)0的(de)話(h≥≠>‍uà),則年(nián)輕代對(duì)象♦€​Ω不(bù)經過Survivor區(qū),直接進↔&入年(nián)老(lǎo)代. 對(duì)于年(n±®ián)老(lǎo)代比較多(duō)的(de)應用(yòng),可(kě)以β∞提高(gāo)效率.如(rú)果将此值設置為(wèi)一(yī)個(gè♠₹✔±)較大(dà)值,則年(nián)輕代對(duì)象會(huì)在S÷≈urvivor區(qū)進行(xíng)多(du₹¶ō)次複制(zhì),這(zhè)樣可(kě)以增加對(duλ₹ì)象再年(nián)輕代的(de)存活 時(shí)間(ε↑∞jiān),增加在年(nián)輕代即被回收的(de)概率
該參數(shù)隻有(yǒu)在串行(xíng)GC時(shí)才∞♠有(yǒu)效.
-XX:ParallelGCThreads 并行(xíng)收集器(qì)的(de)線程數♥♦↔€(shù) 此值最好(hǎo)配置與處理(lǐ)器(qì)數(shù)目相(xi∞→ ₹àng)等 同樣适用(yòng)于CMS
-XX:+AggressiveOpts JDK 5 update 6後引入,但(dàn)需要(yào) ∑₽手動啓用(yòng)。 啓用(yòng)JVM開(kāi)發團隊最新的(de)調優成果'ε•¶。例如(rú)編譯優化(huà),偏向鎖,并行Ω✘ε✘(xíng)年(nián)老(lǎo)代收集等。
JDK6默認啓用(yòng)。
-XX:LargePageSizeInBytes=4m₩≈ 默認4m,amd64位:2m 設置堆的(de)內(nèi)存頁大(dà)小(xiǎo)。
-XX:MaxHeapFreeRatio=☆>∑70 70 GC後,如(rú)果發現(xiàn)空(kōng)閑堆內(nèi)存占到(₹£dào)整個(gè)預估堆內(nèi)存的(de)70₹∏'★%,則收縮堆內(nèi)存預估最大(dà)值。
什(shén)麽是(shì)預估堆內(nèi)存?
預估堆內(nèi)存是(shì)堆大(dà)小&'(xiǎo)動态調控的(de)重要(yào)選項之一(yī)。堆內$↑₽≥(nèi)存預估最大(dà)值一(yī)定小(xiǎo)于α₩或等于固定最大(dà)值(-Xmx指定的(de)數(shù)值)。前¶✔者會(huì)根據使用(yòng)情況動☆€态調大(dà)或縮小(xiǎo),以提高(gāo)÷≥₩GC回收的(de)效率。
-XX:NewSize 設置年(nián)輕代大(dà)小(xiǎo)(for 1.3/1. •4)
-XX:MaxNewSize=size 1.3.1 Sparc: 32m 新生(shēng)代占整個(gè)堆內(n​ ​èi)存的(de)最大(dà)值。
1.3.1 x86: 2.5m
-XX:MaxPermSize=64m 5.0以後: 64 bit VMs會(huì)增大(dà)預設↔♥值的(de)30% Perm占整個(gè)堆內(nèi)存的(d ✔&e)最大(dà)值。
1.4 amd64: 96m
1.3.1 -client: 32m
其他(tā)默認 64m
-XX:MinHeapFreeRatio=40 40 GC後,如(rú)果發現(xiàn)空(kōng)閑堆內​α(nèi)存占到(dào)整個(gè)預估堆內(>αnèi)存的(de)40%,則放(fàng)大(dà)堆•π內(nèi)存的(de)預估最大(dà)值,但(dàn)不(bù♠$★★)超過固定最大(dà)值。
關聯選項:
-XX:MaxHeapFreeRatio=70
-XX:NewRatio=2 Sparc -client: 8 新生(shēng)代和(hé)年(nián)老(©€lǎo)代的(de)堆內(nèi)存占用(yò™∞↓ng)比例。
這(zhè)裡(lǐ)的(de)2表示,新生'¥α®(shēng)代占最大(dà)堆內(nèi)存的(d♥∑e)1/2。也(yě)就(jiù)是(shì)和(hé)年(nián)→←>"老(lǎo)代平分(fēn)堆的(de)占用(y<₽‌​òng)。
x86 -server: 8
x86 -client: 12
-client: 4 (1.3)
8 (1.3.1+)
x86: 12
其他(tā)默認 2
-XX:NewSize=2.125m 5.0以後: 64 bit Vms會(huì)增大≥"÷'(dà)預設值的(de)30% 新生(shēng)代預估堆內(nèi)存占用(yòng)的(de)默認值。(什λα(shén)麽是(shì)預估堆內(nèi)存Ω$​↓?見(jiàn) -XX:MaxHeapFreeRatio®• 處的(de)描述)
x86: 1m
x86, 5.0以後: 640k
其他(tā)默認 2.125m
-XX:ReservedCodeCacheSize=32m &n♦$‍♥bsp;  Solaris 64-bit, amd64, -s‌®±∑erver x86: 48m 設置代碼緩存的(de)最大(dà)值,編譯用(yòng)。
1.5.0_06之前, Solaris 64-γ bit amd64: 1024m
其他(tā)默認 32m
-XX:SurvivorRatio=8 Solaris amd64: 6 Eden與Survivor的(de)占用(yòng)比例。這(zhè)ε↓↕δ裡(lǐ)的(de)8表示,一(yī)個(¶‌gè)survivor區(qū)占用(yòng) 1/8 的(d€✔↓e)新生(shēng)代內(nèi)存,因為(wèi)survivor有(y£♠ ∑ǒu)2個(gè),所以是(shì) 2/8,那©£‌☆(nà)麽Eden的(de)占比為(wèi) 6/8。
Sparc in 1.3.1: 25
Solaris platforms5.0以前: 3€≠∏2
其他(tā)默認 8
-XX:TargetSurvivorRatio=50 50 實際使用(yòng)的(de)survivor空(kōng)間(j→ ♠iān)大(dà)小(xiǎo)占比。默認是(≥↓$↑shì)50%,最高(gāo)90%。
-XX:ThreadStackSize=512 Sparc: 512 線程堆棧大(dà)小(xiǎo)
Solaris x86: 320(5.0以前 ∑♣↔256)
Sparc 64 bit: 1024
Linux amd64: 1024 (5.0 以前 0)
其他(tā)默認 512.
-XX:+UseBiasedLocking JDK 5 update 6後引入,但(dàn)需要(yào)手動啓用(y‍®δ↓òng)。 啓用(yòng)偏向鎖。
JDK6默認啓用(yòng)。
-XX:+UseFastAccessorMethods 默認啓用(yòng) 啓用(yòng)原始類型的(de)getter方法優化(huà​↔¶)。
-XX:-UseISM 默認啓用(yòng) 啓用(yòng)solaris的(de)ISM。
詳見(jiàn)Intimate Shared Memory.
-XX:+UseLargePages JDK 5 update 5後引入,但(dàn‌♦)需要(yào)手動啓用(yòng)。 啓用(yòng)大(dà)內(nèi)存分(fēn)頁。
JDK6默認啓用(yòng)。
-XX:+UseMPSS 1.4.1 之前: 不(bù)啓用(yòng) 啓用(yòng)solaris的(de)MPSS,不(bù)能(n∏>₹éng)與ISM同時(shí)使用(yòng)。
其餘版本默認啓用(yòng)
-XX:+StringCache 默認啓用(yòng) 啓用(yòng)字符串緩存。
-XX:AllocatePrefetchLines=1↑β→  1 與機(jī)器(qì)碼指令預讀(dú)相(xià÷γ ng)關的(de)一(yī)個(gè)選項,資料比較少(shǎo),本文(w>∏®πén)檔不(bù)做(zuò)解釋。有(yǒu)興趣的(de)朋(pé≤∑ng)友(yǒu)請(qǐng)自(zì)行(xíng)閱δ™ε讀(dú)官方doc。
-XX:AllocatePrefetchStyle₩γ♠=1 1 與機(jī)器(qì)碼指令預讀(dú)相(xiàng)關的(de)一(yī÷↕γ)個(gè)選項,資料比較少(shǎo),本文(wé€∞n)檔不(bù)做(zuò)解釋。有(yǒu)興趣的(de)≤→♦朋(péng)友(yǒu)請(qǐng)自(zì)行(xíng)閱讀(d→§↓ú)官方doc。
-XX:-AllowUserSignalHandlers 限于Linux和(hé)Solaris,默認不(bù)啓♣≈用(yòng) 允許為(wèi)java進程安裝信号處理(<"lǐ)器(qì)。
-XX:-DisableExplicitGC 默認不(bù)啓用(yòng) 禁止在運行(xíng)期顯式地(dì)調用(yòng) Syste>↑m.gc()。
開(kāi)啓該選項後,GC的(de)觸  ♠☆發時(shí)機(jī)将由Garbage Col§ ≠lector全權掌控。
需要(yào)注意的(de)是(shì),你(nǐ)程序裡(lǐ)沒調‍β≠用(yòng)System.gc(),你(nǐ)依賴的(d≈•​e)框架,工(gōng)具可(kě)能(néng$≠)在使用(yòng)。例如(rú)RMI。請(qǐng)仔細€♠權衡禁用(yòng)帶來(lái)的(de)影(yǐng)響。
-XX:-RelaxAccessControlCheck 默認不(bù)啓用(yòng) 在Class校(xiào)驗器(qì)裡(lǐ),放(fà♥λng)松對(duì)訪問(wèn)控制(zhì)的(de)檢查‍↔★。作(zuò)用(yòng)與reflection裡≥'‍₩(lǐ)的(de)setAccessible類似。
-XX:-UseConcMarkSweepGC 默認不(bù)啓用(yòng) 啓用(yòng)CMS低(dī)停頓垃圾收集器(qì)。
-XX:-UseParallelGC 默認不(bù)啓用(yòng),-serveδ±♠♠r時(shí)啓用(yòng) 策略為(wèi)新生(shēng)代使用(yòng)并‍ 行(xíng)清除,年(nián)老(lǎo)代使用(<$≠‌yòng)單線程Mark-Sweep-Compact清除的(de)垃圾收集器♦'φ‍(qì)。
-XX:-UseParallelOldGC 默認不(bù)啓用(yòng) 策略為(wèi)老(lǎo)年(nián)代和(™ hé)新生(shēng)代都(dōu)使用(yòng)并行(xíng)清除 "ε≥的(de)垃圾收集器(qì)。
-XX:-UseSerialGC 默認不(bù)啓用(yòng),-client時(shí)啓用(yòng)>✘∑ 使用(yòng)串行(xíng)垃圾收集器(qì)。
-XX:+UseSplitVerifier java5默認不(bù)啓用(yòng),java6默認啓"♣☆↕用(yòng) 使用(yòng)新的(de)Class類型校(xi→$↔ào)驗器(qì) 。
什(shén)麽是(shì)新Class類α 型校(xiào)驗器(qì)?
新Class類型校(xiào)驗器(qì),将老(lǎo)的(de)校(x×§↔iào)驗步驟拆分(fēn)成兩步:
1,類型推斷。2,類型校(xiào)驗。
新類型校(xiào)驗器(qì)通(tōng"$♣ )過在javac編譯時(shí)嵌入類型信息到(dφ✘♣ào)bytecode中,省略了(le)類型推 ≤斷這(zhè)一(yī)步,從(cóng)而提升了∏±÷(le)classloader的(de)性能(néng)。
Classload順序:load -> verify -↕★π> prepare -> resove ->  ↔¥™init
關聯選項:
-XX:+FailOverToOldVerifier
-XX:+FailOverToOldVerifier Java6新引入選項,默認啓用(yòng) 如(rú)果新的(de)Class校(xiào)驗器(qì)檢查失敗,則使用±><♥(yòng)老(lǎo)的(de)校(xiào≥♥)驗器(qì)。
關聯選項:
-XX:+UseSplitVerifier
-XX:+HandlePromotionFailure  &nbs λ★p;  java5以前是(shì)默認不(bù)啓用(yò₽§∑ng),java6默認啓用(yòng) 關閉新生(shēng)代收集擔保。
什(shén)麽是(shì)新生(shēng)σ£"代收集擔保?
在一(yī)次理(lǐ)想化(huà)的(de)minor g∞✘&₽c中,活躍對(duì)象會(huì)從(cóng)Eden和(hé)Fi€÷£rst Survivor中被複制(zhì)到(dào)Second Su€©βrvivor。然而,Second Survivor不(bù)一(yī)&‍​↓定能(néng)容納所有(yǒu)的(de)≥✔≠活躍對(duì)象。為(wèi)了(le)确保minor gc←₩¶☆能(néng)夠順利完成,需要(yào)在年(nián)老(lǎ$₩↔ o)代中保留一(yī)塊足以容納所有(yǒu)活躍對(♣☆duì)象的(de)內(nèi)存空(kōng)間(jiān)。這(zhè)€♥個(gè)預留的(de)操作(zuò),被稱之為×ε☆(wèi)新生(shēng)代收集擔保(New Gen™♠α<eration Guarantee)。當預留操作(zu♠​ò)無法完成時(shí),就(jiù)會(huì)觸發major gc" ★♠(full gc)。
為(wèi)什(shén)麽要(yào)關閉新生(shēng)代收集擔®↓保?
因為(wèi)在年(nián)老(lǎo)代中γ•預留的(de)空(kōng)間(jiān)大(dà)小(x✘ iǎo),是(shì)無法精确計(jì)算(suφ≠πàn)的(de)。為(wèi)了(le)确保σ←£極端情況的(de)發生(shēng),GC參考了(l±σe)最壞情況下(xià)的(de)新生(shē✔σng)代內(nèi)存占用(yòng),即Eden+Fi↔∏rst Survivor。這(zhè)種策略‍α∏無疑是(shì)在浪費(fèi)年(nián)老(lǎo)代內(nèi)≥≥存,并從(cóng)時(shí)序角度看(k↕<àn),可(kě)能(néng)提前觸發Full GC。∑₩ε±為(wèi)了(le)避免如(rú)上(shàng)情況的(de)發♣π生(shēng),JVM允許開(kāi)發者關閉新生(shē₹§ng)代收集擔保。
在開(kāi)啓本選項後,minotr gc将不(bλ✔∏ù)再提供新生(shēng)代收集擔保,而是(shì)在出現(x  iàn)survior或年(nián)老(α→'lǎo)代不(bù)夠用(yòng)時(shí),抛出promotion✔γ failed異常。
-XX:+UseSpinning java1.4.2和(hé)1.5需要(yào)手動₽↓啓用(yòng), java6默認已啓用(yòng) 啓用(yòng)多(duō)線程自(zì)旋鎖優化(huà)。
自(zì)旋鎖優化(huà)原理(lǐ)
大(dà)家(jiā)知(zhī)道(dào)γ≈ ↓,Java的(de)多(duō)線程安全是(shì)基于Lock機✔¥(jī)制(zhì)實現(xiàn)的(de),而Lo₹•ck的(de)性能(néng)往往不(bù)如(rú)人(rén)$ β意。原因是(shì),monitorente§↓r與monitorexit這(zhè)兩個(gè)控制(zhì)多←₩ (duō)線程同步的(de)byteco§​de原語,是(shì)JVM依賴操作(zuò)系統互斥(mutex©£)來(lái)實現(xiàn)的(de)。互斥是(shì)¥"♠一(yī)種會(huì)導緻線程挂起,并在較短(duǎn)的(de)時(π≈→₩shí)間(jiān)內(nèi)又(yòu)需要(yào)重☆®±新調度回原線程的(de),較為(wèi)消耗資源的(de)操作(zuò)。‌& "為(wèi)了(le)避免進入OS互斥, × Java6的(de)開(kāi)發者們提出了(le)自(zì)旋®÷鎖優化(huà)方法。自(zì)旋鎖優化(h€★uà)的(de)原理(lǐ)是(shì)在線程進入OS互斥前,通(t↔ ​•ōng)過CAS自(zì)旋一(yī)定的(de)次數(shù)來(lá✔ i)檢測鎖的(de)釋放(fàng)。如(rú)果在自(zì)旋次數(s'™αhù)未達到(dào)預訂值前,發現(xiàn)鎖已被♣'•₽釋放(fàng),則會(huì)立即持有(yǒu)該鎖。
CAS檢測鎖的(de)原理(lǐ)詳見(jiàn): 關聯選項:
-XX:PreBlockSpin=10
-XX:PreBlockSpin=10 -XX:+UseSpinning必須先啓用(yòng),對(du∏₩ì)于java6來(lái)說(shuō)已經≠‌默認啓用(yòng)了(le),這(zh∑ ∑è)裡(lǐ)默認自(zì)旋10次 控制(zhì)多(duō)線程自(zì)旋鎖優化(huà)的(de)自(✔§₽zì)旋次數(shù)。(什(shén)麽是(shì)自§≈≤β(zì)旋鎖優化(huà)?見(jiàn) -XX:+UseS&§pinning 處的(de)描述)
關聯選項:
-XX:+UseSpinning
-XX:+ScavengeBeforeFullGC   ↓φ λ;  默認啓用(yòng) 在Full GC前觸發一(yī)次Minor GC。
-XX:+UseGCOverheadLimit 默認啓用(yòng) 限制(zhì)GC的(de)運行(xíng)時(shí)間(jiān¶‌)。如(rú)果GC耗時(shí)過長(cháng),就(jiù)抛OOM。σ∞
-XX:+UseTLAB 1.4.2以前和(hé)使用(yòng)-clien→≠φt選項時(shí),默認不(bù)啓用(y∏©÷§òng),其餘版本默認啓用(yòng) 啓用(yòng)線程本地(dì)緩存區(qū)(T¥Ω₹hread Local)。
-XX:+UseThreadPriorit±≠ies 默認啓用(yòng) 使用(yòng)本地(dì)線程的(de)₹∞‍ 優先級。
-XX:+UseAltSigs 限于Solaris,默認啓用(yòng) 為(wèi)了(le)防止與其他(tā)發送信号的(de)應用(y≠®¶&òng)程序沖突,允許使用(yòng)候補信号™φ替代 SIGUSR1和(hé)SIGUSR2。
-XX:+UseBoundThreads 限于Solaris, 默認啓用(yòng) 綁定所有(yǒu)的(de)用(yòng)戶線程到(dàoπ×∞ )內(nèi)核線程。
減少(shǎo)線程進入饑餓狀态(得(de)不(bù)到(φ$dào)任何cpu time)的(de)次'↕®數(shù)。
-XX:+UseLWPSynchronization 限于solaris,默認啓用(yòng) 使用(yòng)輕量級進程(內(nèi)核線程)替換線程同步。
-XX:+MaxFDLimit 限于Solaris,默認啓用(yòng) 設置java進程可(kě)用(yòng)文(wén)件(jiànγ ♥☆)描述符為(wèi)操作(zuò)系統允許的(de)最大(dà)值。
-XX:+UseVMInterruptibleIO 限于solaris,默認啓用(yòng) 在solaris中,允許運行(xíng)時(s∑$↕hí)中斷線程 。
-XX:CMSInitiatingOccupancyFraction=7≤∏÷↔0 92 使用(yòng)cms作(zuò)為(w♠≠&σèi)垃圾回收 使用(yòng)70%後¥★開(kāi)始CMS收集 為(wèi)了(le)保證不(bù)出現(xià♠αn)promotion failed(見(jiàn)π≈下(xià)面介紹)錯(cuò)誤,該值的(de)設置需要(yào§↕)滿足以下(xià)公式CMSInitiatingOccupancyFr&£÷§action計(jì)算(suàn)公式

 

調試選項

選項與默認值 默認值與限制(zhì) 描述
-XX:-CITime 1.4引入。 打印JIT編譯器(qì)編譯耗時(shí♣≠↓)。
默認啓用(yòng)
-XX:ErrorFile=./hs_err_pid<pid→π®>.log Java 6引入。 如(rú)果JVM crash後,将錯(cuò)誤日(rì)志(zhì♦λ<¥)輸出到(dào)指定目錄。
-XX:-ExtendedDTraceProb↑¥Ωes Java6引入,限于solaris 啓用(yòng)dtrace診斷。
默認不(bù)啓用(yòng)
-XX:HeapDumpPath=./java_pid&♦✘lt;pid>.hprof &n∞ ≥bsp;  默認是(shì)java進程啓動位置,即user.dir 堆內(nèi)存快(kuài)照(zhào)的₩∑(de)存儲路(lù)徑。
什(shén)麽是(shì)堆內(nèi)存快(kuài)照(zhào× ☆Ω)?
當java進程因OOM或crash被強制(zhì)退出✘♥€後,生(shēng)成hprof(Heap <☆✘≈PROFling)格式的(de)堆快(kuài™×<)照(zhào)文(wén)件(jiàn)。用(yòngλ ✘)于出問(wèn)題後調試,診斷。文(wén)件(jiàn)名一(φ''♦yī)般為(wèi)java_<pi↔∑d>_<date>_&∞→£lt;time>_heapDump.hprof 'δ.
解析快(kuài)照(zhào)文(wén)件(jiàn),可(kěσ )以使用(yòng) jhat, eclipse MAT,gdb等工(gōng¥☆)具。
-XX:-HeapDumpOnOutOfMemoryError 1.4.2 update12 和(hé) 5λ↔λ.0 update 7 引入。 在OOM時(shí),輸出一(yī)個(gè)dump.core文(wén™γ)件(jiàn),記錄當時(shí)的(de)堆內(nèi)存快(kuài)照$≠(zhào)(什(shén)麽是(shì)堆內(nèi)存快(≈©kuài)照(zhào)? 見(jiàn) -XX:HeapDum αpPath 處的(de)描述)。
默認不(bù)啓用(yòng)
-XX:OnError="<cmd args>;<cmd a&Ω©rgs>" 1.4.2 update 9引入 當java每抛出一(yī)個(gè)ERROλ✔♥R時(shí),運行(xíng)指定命令行(xíng)指令集。指令集是∏‌≈♥(shì)與OS環境相(xiàng)關的(de),在linux下(xià)多§≠(duō)數(shù)是(shì)bash腳本,windows下(xià)是(→♣γshì)某個(gè)dos批處理(lǐ)。
-XX:OnOutOfMemoryError="←±©&<cmd args>;<cmd args>"<>¶ 1.4.2 update 12和(hé)java6時(Ω∏shí)引入 當第一(yī)次OOM時(shí),運行(xíng)指定命令行(​∞≈xíng)指令集。指令集是(shì)與OS環境相(xi ε≠àng)關的(de),在linux下(xià)多(duō)數(s×↕ hù)是(shì)bash腳本,window÷✔s下(xià)是(shì)某個(gè)dos批處理(lǐ)。
-XX:-PrintClassHistogram✘δ  默認不(bù)啓用(yòng) 打印class柱狀圖,圖中除了(le)class,π∏&還(hái)有(yǒu)該class的(de)in÷β&αstance統計(jì)信息。
Windows下(xià), 按ctrl-break時(shí)。
Linux下(xià)是(shì)執行(xíng)kill -3,或發送S₹↔→IGQUIT信号。
Jmap ?histo pid也(yě)實現(x¥λ<€iàn)了(le)相(xiàng)同的(de)功能(néng☆$ γ)。詳見(jiàn) http://java.sun.co​®m/javase/6/docs/techn•≠£otes/tools/share/jmap.html
-XX:-PrintConcurrentLocks 默認不(bù)啓用(yòng) 在線程dump時(shí),順便打印java.uφβ<til.concurrent鎖狀态。
Jstack ?l pid 也(yě)同樣實現(xiàn)了(le)相(‍₩♦¥xiàng)同的(de)功能(néng)。詳見(jiàn) http://jε ÷ava.sun.com/javase/6/docs/§≥​ technotes/tools/share/jstack.html
-XX:-PrintCommandLineFlags 5.0 引入,默認不(bù)啓用(yòng) Java啓動時(shí),往stdout打印當前啓用(≠™&↔yòng)的(de)非穩态jvm options。
例如(rú):
-XX:+UseConcMarkSweepGC -XX:+He≈σ♣apDumpOnOutOfMemoryError -XX:+DoEs±×®capeAnalysis
-XX:-PrintCompilation 默認不(bù)啓用(yòng) 打印方法被JIT編譯時(shí)的(de)信息到(dào♠<")stdout。
例如(rú):
java.lang.String::charAt (33 ♥ ‍ bytes)
-XX:-PrintGC 默認不(bù)啓用(yòng) 開(kāi)啓GC日(rì)志(zhì)打印€×∞。
例如(rú):
[Full GC 131115K->7482K(1015808K¥ ↔), 0.1633180 secs]
該選項可(kě)通(tōng)過 com.sun.management.∞∑HotSpotDiagnosticMXBean API 和(h$∞®♣é) Jconsole 動态啓用(yòn♠∏g)。詳見(jiàn) http://java.sun←↔✔.com/developer/technicalArticles$γ/J2SE/monitoring/#Heap_Dump
-XX:-PrintGCDetails 1.4.0引入,默認不(bù)啓用(yòng) 打印GC回收的(de)細節。
例如(rú):
[Full GC (System) [Tenuᣕred: 0K->2394K(466048K)§±, 0.0624140 secs] 30822K->2394★∑β<K(518464K), [Perm : 10443K-&₩←gt;10443K(16384K)], 0.0625410  >↕₹secs] [Times: user=0≈£∞™.05 sys=0.01, real=0.06 secs]
該選項可(kě)通(tōng)過 com.sun.managem£γ ↕ent.HotSpotDiagnosticMXBean API 和(hé)± © Jconsole 動态啓用(yòng)。詳見(jiàn) http://j♥"±‌ava.sun.com/developer/tech">λ↓nicalArticles/J2SE/monitoring/#Heap_Dum&♦™p
-XX:-PrintGCTimeStamps 默認不(bù)啓用(yòng) 打印GC停頓耗時(shí)。
例如(rú):
2.744: [Full GC (System) 2.744: [Tenβ£ured: 0K->2441K(466048←≤K), 0.0598400 secs] 31754K->2441K(51→™8464K), [Perm : 10717₽♦≈ K->10717K(16384K)]"✔φ , 0.0599570 secs] [Times: u αδser=0.06 sys=0.00, real=₽ ₩®0.06
secs]
該選項可(kě)通(tōng)過 com.§™∞"sun.management.HotSpotDiagnosticMσ XBean API 和(hé) Jconsole ™✘÷動态啓用(yòng)。詳見(jiàn) http://java.su≠♣n.com/developer/technicalArt♥★☆icles/J2SE/monitoring/#Heap_Dump
-XX:-PrintTenuringDistribution 默認不(bù)啓用(yòng) 打印對(duì)象的(de)存活期限信息。
例如(rú):
[GC
Desired survivor size 4653056 bytβ↔±es, new threshold 32 (maβ≤π¶x 32)
- age 1: 2330640 bytes, 2330640♦™ total
- age 2: 9520 bytes, 23401↔•60 total
204009K->21850K(5152π©00K), 0.1563482 secs] π
Age1 2表示在第1和(hé)2次GC後存活的(φ★∞de)對(duì)象大(dà)小(xiǎo)。
-XX:-TraceClassLoading 默認不(bù)啓用(yòng) 打印class裝載信息到(dào)stdout。記Loaσ€ded狀态。
例如(rú):
[Loaded java.lang.Object ₩ε♠from /opt/taobao/install/jdk1.6.0_0±>7/jre/lib/rt.jar]
-XX:-TraceClassLoadingPreorder 1.4.2引入,默認不(bù)啓用(yòng) 按class的(de)引用(yòng)/依賴順序打印類裝載Ω€®信息到(dào)stdout。不(bù)同于 TraceClassLα≈πoading,本選項隻記 Loading狀态。
例如(rú):
[Loading java.lang.Object from ​¶✘/home/confsrv/jdk1.6.Ω♣&♥0_14/jre/lib/rt.jar]
-XX:-TraceClassResolution 1.4.2引入,默認不(bù)啓用(yòng) 打印所有(yǒu)靜(jìng)态類,常量的(de↔✔$)代碼引用(yòng)位置。用(yòng)于debuε®g。
例如(rú):
RESOLVE java.util.Hash™φMap java.util.HashMap$Ent≠'γry HashMap.java:209
說(shuō)明(míng)HashMap類的(de)209行♣∞♦(xíng)引用(yòng)了(le)靜(jìng)态類 javaσ≠≈±.util.HashMap$Entry
-XX:-TraceClassUnloading 默認不(bù)啓用(yòng) 打印class的(de)卸載信息到(dà↑≈o)stdout。記Unloaded狀态。
-XX:-TraceLoaderConstraints Java6 引入,默認不(bù)啓用(yòng) 打印class的(de)裝載策略變化(huà)信息∞λ★γ到(dào)stdout。
例如(rú):
[Adding new constraint for ¥♥¶name: java/lang/String, loader[0]α$€↔: sun/misc/Launcher$ExtCla↑✘¶≠ssLoader, loader[1]: <boπ &♥otloader> ]
[Setting class object in $↑₽existing constraint for name: [Ljav♠Ωa/lang/Object; and loa♦©der sun/misc/Launcher$ExtClassLoaδ©€der ]
[Updating constraint fo¶Ωr name org/xml/sax/InputSource, ₩‌∞"loader <bootloader>¥≤​;, by setting class object ]
[Extending constraint for name java$‌∞/lang/Object by adding l×Ω≈★oader[15]: sun/reflecγ☆β✘t/DelegatingClassLoader  ]
裝載策略變化(huà)是(shì)實現(xiàn)classloader©≤↕↓隔離(lí)/名稱空(kōng)間(ji≥✔↓ān)一(yī)緻性的(de)關鍵技(jì)術(shù)。
-XX:+PerfSaveDataToFile 默認啓用(yòng) 當java進程因OOM或crash被強制(zhì)退出後,生(shēngφ£ε<)成一(yī)個(gè)堆快(kuài)照(zhào)文(wén)件(∏α♦™jiàn)(什(shén)麽是(shì)堆≠π內(nèi)存快(kuài)照(zhào)?←↔β 見(jiàn) -XX:HeapDumpPath 處的(‍α↔de)描述)。

 

四、  經驗

     1.年(nián)輕代大 β₽ (dà)小(xiǎo)選擇

      &n♣Ω☆bsp;  1)響應時(shí)間(jiān)優先的(de)應用₩≤(yòng):盡可(kě)能(néng)設大(dà),直到(dα♥βào)接近(jìn)系統的(de)最低(dī)響應時(shí)間(j>©iān)限制(zhì)(根據實際情況選擇).在此種情況下(xià),年€∞↔(nián)輕代收集發生(shēng)的(d↔ β★e)頻(pín)率也(yě)是(shì)最小(xiǎo)的(de).同↓'←時(shí),減少(shǎo)到(dào)達年(nián)老(lǎo)代的(≤γδde)對(duì)象.

    &ε§nbsp;  &nbs™♦®p; 2)吞吐量優先的(de)應用(yòng):盡可(kě)能(→↔néng)的(de)設置大(dà),可(kě)能(néng)到(dào)達¥✔ΩGbit的(de)程度.因為(wèi)對(d↓≠uì)響應時(shí)間(jiān)沒有(yǒu)要(yà§☆→£o)求,垃圾收集可(kě)以并行(xíng)進行(xíng),一(yī)↓‌般适合8CPU以上(shàng)的(de)應用(yò©®λ≥ng).

     →​;     3)避免設置♦ >∑過小(xiǎo).當新生(shēng)代設置過小(xiǎo)時(s↑≈•λhí)會(huì)導緻:1.YGC次數(shù)更加頻(pín)繁 ♦•2.可(kě)能(néng)導緻YGC對(duì)象直接進入舊(jiù)生(s¶☆♦✘hēng)代,如(rú)果此時(shí)舊(jiùε×∞¥)生(shēng)代滿了(le),會(huì)觸發FGC.

     2.年(nián)老(lǎ±Ω ™o)代大(dà)小(xiǎo)選擇

      &n$​≠bsp;  1)響應時(shí)間(jiān)優先的(de)應用(yΩγ$òng):年(nián)老(lǎo)代使用(yòng)≥φ λ并發收集器(qì),所以其大(dà)小(x‍β≤ iǎo)需要(yào)小(xiǎo)心設置,一(yī)般&¥σ要(yào)考慮并發會(huì)話(huà)率和(hé)會(huì)δ☆≈★話(huà)持續時(shí)間(jiān)等一(yī)些(xiē∞±)參數(shù).如(rú)果堆設置小(xiǎo)了(le),可(kě)以會& ₽(huì)造成內(nèi)存碎 片,高('λπgāo)回收頻(pín)率以及應用(yò♠£¶♠ng)暫停而使用(yòng)傳統的(de)标記清除方式↕♦β ;如(rú)果堆大(dà)了(le),則需要♠'(yào)較長(cháng)的(de)收集時(shí)間(jiān).最優化(Ωφ★huà)的(de)方案,一(yī)般需要(yào)參考以下(x¥§ ià)數(shù)據獲得(de): 并發垃圾收集信© ♥息、持久代并發收集次數(shù)、傳統GC信息、花(huā)∞σ在年(nián)輕代和(hé)年(nián)老(lǎo)代回收上(shàng)₩ε∑≤的(de)時(shí)間(jiān)比例。

     &α↔$nbsp;   2)吞吐量優先的(de)應用(yòng¥>):一(yī)般吞吐量優先的(de)應用(♠★yòng)都(dōu)有(yǒu)一(yī)個(gè)很← (hěn)大(dà)的(de)年(nián)輕代和(hé)一(yī)個(gè☆δ×)較小(xiǎo)的(de)年(nián<∏)老(lǎo)代.原因是(shì),這(zhè)樣可 ∑→‌(kě)以盡可(kě)能(néng)回收掉大(dà)&©部分(fēn)短(duǎn)期對(duì)象,減少(shǎo)中☆₽•期的(de)對(duì)象,而年(nián)老(lǎo)代盡存放(fà★‌ng)長(cháng)期存活對(duì)象.

     3.較小(xi✘ •ǎo)堆引起的(de)碎片問(wèn)題:promotion failed←>™∞

     γ≥€    1)÷☆→因為(wèi)年(nián)老(lǎo)代的(de)并發收集器(qì)♦♣γ使用(yòng)标記,清除算(suàn)法,所以不(bù)會(huì)對(duγ&ì)堆進行(xíng)壓縮.當收集器(qì)回收時★δ(shí),他(tā)會(huì)把相(xiàng)鄰的(de)空(kōng©&₹ε)間(jiān)進行(xíng)合并,這(zhè)樣可'✔≥™(kě)以分(fēn)配給較大(dà)的(de)對(duì)象.但(dà✘Ωn)是(shì),當堆空(kōng)間(jiān)較小(xiǎo)×£↓Ω時(shí),運行(xíng)一(yī)段時(shí)間(jiān)以後,就(‍×Ω↕jiù)會(huì)出現(xiàn)"碎片",如(rú)果并發收集器(qìΩ±)找不(bù)到(dào)足夠的(de)空(kōng)間(jiλ∏ 'ān),那(nà)麽并發收集器(qì)将會∞✔α∞(huì)停止,然後使用(yòng)傳統的(de)标記,清★λ¥✔除方式進行(xíng)回收.如(rú)果出現(xià↔≥®n)"碎片",可(kě)能(néng)需要 γ♠★(yào)進行(xíng)如(rú)下(xià)配置:

-XX:+UseCMSCompactAtFullCollection:使用<®(yòng)并發收集器(qì)時(shí),開(kāi)啓對₩‌↑∏(duì)年(nián)老(lǎo)代的(de)壓縮.

-XX:CMSFullGCsBeforeCompaction=0:上ε§₽±(shàng)面配置開(kāi)啓的(de)情況下(xi"€♦à),這(zhè)裡(lǐ)設置多(duō)少(shǎo)次Fulδ"l GC後,對(duì)年(nián)老(lǎo)代進行(xíng)壓←<€¶縮

     4.用(yòng)64位↔≥操作(zuò)系統Linux下(xià)64位的(de)jdk比32位jdk要(y δào)慢(màn)一(yī)些(xiē),但(dàn)是(shì)吃(chīβ€☆∏)得(de)內(nèi)存更多(duō),吞吐量更大(dà)

     5φ£✔.XMX和(hé)XMS設置一(yī)樣大(dà),¥≠•↕MaxPermSize和(hé)MinPermSize設置一(yī​÷♣)樣大(dà),這(zhè)樣可(kě)以減輕伸縮堆大(dà)小(xiǎo)帶≠✔'¶來(lái)的(de)壓力

     6.使用(yònδ♠g)CMS的(de)好(hǎo)處是(shì)用(yò€±λ<ng)盡量少(shǎo)的(de)新生(shēnε♣g)代,經驗值是(shì)128M-256M, 然後老(l€πǎo)生(shēng)代利用(yòng)CMS并行(xíng)收集, 這(zhεα£↑è)樣能(néng)保證系統低(dī)延遲的(de)吞吐效♥δ∏率。 實際上(shàng)cms的(de)收集停頓時(shα§λ¶í)間(jiān)非常的(de)短(duǎ₩£n),2G的(de)內(nèi)存, 大(dà)約20-80γ★ms的(de)應用(yòng)程序停頓時(shí)間(jiān)

     7.α♦系統停頓的(de)時(shí)候可(kě)能(néng)是§''(shì)GC的(de)問(wèn)題也(yě)可(k♣★™×ě)能(néng)是(shì)程序的(de)問(wèn)題,多(duō)用∏Ω€$(yòng)jmap和(hé)jstack查看(kàn),或者♦π₩<killall -3 java,然後查看(kàn)java控制(zhì)台日≠↓>(rì)志(zhì),能(néng)看(kàn)出很(hěn)多(duō‍​ε♥)問(wèn)題。(相(xiàng)關工(gōng‌→→λ)具的(de)使用(yòng)方法将在後面的(de)blog中介紹)

    ♦♣; 8.增加Heap的(de)大(dà)小(xiǎo)雖然∏✔∑會(huì)降低(dī)GC的(de)頻(pín)率,¥β '但(dàn)也(yě)增加了(le)每次GC的(de)時(sh↑←í)間(jiān)。并且GC運行(xíng)時(shí),所有(yǒ¶ φ•u)的(de)用(yòng)戶線程将暫停,也‌★<α(yě)就(jiù)是(shì)GC期間(jiān),Java應用(yòng<←)程序不(bù)做(zuò)任何工(gōng)作♥♥(zuò)。

   &nb ¥sp; 9.Heap大(dà)小(xiǎo)并不(bù)決"λ £定進程的(de)內(nèi)存使用(yòn&'¶<g)量。進程的(de)內(nèi)存使用(yòng)量要(yào)大(dà)于ε¥-Xmx定義的(de)值,因為(wèi)Java為(wèi)其他(tā♥∞)任務分(fēn)配內(nèi)存,例如(rú)每個(gè)線程的 ↕∏Ω(de)Stack等。

每個(gè)線程都(dōu)有(yǒu)他(tāλ↑→)自(zì)己的(de)Stack。-Xss

Stack的(de)大(dà)小(xiǎo)限制(zhì)著(zhe)線程​"©的(de)數(shù)量。如(rú)果St♠α☆ack過大(dà)就(jiù)好(hǎo∑ ✔ )導緻內(nèi)存溢漏。-Xss參數(shù)決定Stack大λ (dà)小(xiǎo),例如(rú)-Xss1024K。如(rú)←↔₹ 果Stack太小(xiǎo),也(yě)會(huì)導Ω¥ ×緻Stack溢漏。

   &nbλ≤sp; 10.Java線程的(de)內(nèi)存 ±←♣是(shì)位于JVM或操作(zuò)系統的(de)棧(Stack)空(kōσ<ng)間(jiān)中,不(bù)同于對(duì)象――是(sh<&δΩì)位于堆(Heap)中。這(zhè)是(shì)很(h δěn)多(duō)新手程序員(yuán)容易誤解的(de)地(✘ββ©dì)方。注意,“Java線程的(de)內(nèi)∑$÷¶存”這(zhè)個(gè)用(yòng)詞¥¥∑δ不(bù)是(shì)指Java.lang↔±∞¶.Thread對(duì)象的(de)內(nèi)存,java.laσ€ng.Thread對(duì)象本身(shēn)是(shì™φ✘)在Heap中分(fēn)配的(de),←λ≈β當調用(yòng)start()方法之後,JVM會(huì) ↓≈創建一(yī)個(gè)執行(xíng)單元,最終會(huì∏€↔)創建一(yī)個(gè)操作(zuò)系統的(de)n↔¶ative thread來(lái)執行(xíng),而這§§(zhè)個(gè)執行(xíng)單元或native thread∏‍& 是(shì)使用(yòng)Stack內(nèi)存空(kōng)間(jiān↑​)的(de)。

     11.VM進程的(d∞'>∏e)內(nèi)存大(dà)緻分(fēn)為λ>→(wèi)Heap空(kōng)間(jiān)和(≠↔'hé)Stack空(kōng)間(jiān)兩部分↔±♠(fēn)。Heap又(yòu)分(fēn)為(wèi)Young、O"≥™ld、Permanent三個(gè)代。Stac&↔$k分(fēn)為(wèi)Java方法棧和(hé)native方法棧(不(b≥∏ù)做(zuò)區(qū)分(fēn)),在Stack內(nèi)存區(qū →∏¥)中,可(kě)以創建多(duō)個(gè)線程棧,每個(gè)線©®↕程棧占據Stack區(qū)中一(yī)¥¶↕γ小(xiǎo)部分(fēn)內(nèi)存,線程棧是(shì)一(yī)個(g®♣‌≠è)LIFO數(shù)據結構,每調用(yòng)一(yī)個(gè)方法,會(hu₽®γì)在棧頂創建一(yī)個(gè)Frame,方法返回時(shí)&✘,相(xiàng)應的(de)Frame會(huì)從(cóng)棧頂'Ω移除(通(tōng)過移動棧頂指針)。在這‍±(zhè)每一(yī)部分(fēn)內(nèi)存中,φ'±​都(dōu)有(yǒu)可(kě)能(néng)會(huì)出現(xiàn∑♣¥₽)溢出錯(cuò)誤

     12.仔細了(↔↕ le)解自(zì)己的(de)應用(yòng),如(rú)果用(yòng ¥)了(le)緩存,那(nà)麽年(nián)老(lǎo)<★∏代應該大(dà)一(yī)些(xiē),緩存的(de)HashMap不(bù✘✔δ)應該無限制(zhì)長(cháng),建議(yì)采用(yòng)LR☆≤αU算(suàn)法的(de)Map做(zuò)緩存,LRUMap的(de)​∞™¶最大(dà)長(cháng)度也(yě)要(yào)根據實際情況設定←‍™σ。

    ​>•<; 13.采用(yòng)并發回收時(shí),年(nián)>≤輕代小(xiǎo)一(yī)點,年(nián)老(lǎo)代要(y£↕©←ào)大(dà),因為(wèi)年(nián)老(lǎo)大(αΩdà)用(yòng)的(de)是(shì)并發回收,即使時(shí)間(jiā$∑↕™n)長(cháng)點也(yě)不(bù)會(σ±→×huì)影(yǐng)響其他(tā)程序繼續β<運行(xíng),網站(zhàn)不(bù)會(huì)停¥★♥±頓

     14.↓δ÷JVM參數(shù)的(de)設置(特别是(shì) ?Xmx &•?Xms ?Xmn -XX:SurvivorRatio&±¥≥αnbsp;-XX:MaxTenuringThreshφ✔old等參數(shù)的(de)設置沒有(yǒu)一(y★ λī)個(gè)固定的(de)公式,需要(yào'®πγ)根據PV old區(qū)實際數(shù)據 YGC次數(shù)等∞&★♣多(duō)方面來(lái)衡量。為(wα<↕èi)了(le)避免promotion faild可(k&¶λě)能(néng)會(huì)導緻xmn設置偏小(xiλ±‌ǎo),也(yě)意味著(zhe)YGC的♦ (de)次數(shù)會(huì)增多(duō),處理(lǐΩ←≈)并發訪問(wèn)的(de)能(néng)力下(xià)降等 ±問(wèn)題。每個(gè)參數(shù)的(de)調整都(dō✔€u)需要(yào)經過詳細的(de)性能(néng)測試,才能(néng)找到(dào)特定應用(yòng)™φδ•的(de)最佳配置。

五、  常見(jiàn)內(nèi)₹←∏存錯(cuò)誤及解決方案

     1.γπ∞OutOfMemoryError在開(kāi)發過程中是(shì)司空∏ ε(kōng)見(jiàn)慣的(de),遇到(d↓ &ào)這(zhè)個(gè)錯(cuò)誤,新手程序員★>(yuán)都(dōu)知(zhī)道(dào)從(cóng)兩個(gè)™←方面入手來(lái)解決:一(yī)是(shì)排查程序是(shì)否有(y <ǒu)BUG導緻內(nèi)存洩漏;二是  (shì)調整JVM啓動參數(shù)增大(dà)內(nèi)存。OutOασ♦★fMemoryError有(yǒu)好(hǎo)幾≥ 種情況,每次遇到(dào)這(zhè)個(gè★★)錯(cuò)誤時(shí),觀察OutOfMemor♠×yError後面的(de)提示信息,就(jiù)可(kě)以發現(xià÷∑βn)不(bù)同之處,如(rú):

  1. java.lang.OutOfMemoryError: Ja₩♥∞va heap space&nb♠₩&sp; 
  2. java.lang.OutOfMemoryError: una≈↓✘ble to cre&Ω®'ate newnative thread&↔γ€nbsp; 
  3. java.lang.OutOfMemoryError:&§©βnbsp;PermGen space  
  4. java.lang.OutOfMemoryError: Reδ§¥∏quested array sizeexceeds&nb∞×sp;VM limit  ✘'"₩;
java.lang.OutOfMemoryE↕ ↕λrror: Java heap spacπ&e java.lang.OutOfMemoryπ✔₹Error: unable to creaβπ™te newnative thread java.lang.OutOfMe±♠♠moryError: PermGen space java.♦♠lang.OutOfMemoryError: Requested arra <y sizeexceeds VM limit

     2.java.lang.Ou<λtOfMemoryError:Java hβΩeap space

     &↓γ∑♥nbsp;   1)原因:Heap內(nèi¥​)存溢出,意味著(zhe)Young和(hé)Olπ£δd generation的(de)內(nèi)存不↑>(bù)夠。

      &nb♥≈×✘sp;  2)解決:調整javaπ↑啓動參數(shù) -Xms -Xmx 來(lái)增加Heap內(&πφnèi)存。

     ∏<‌∑3.java.lang.OutOfMemoryError:unable toδ♦•☆ create new native thread♠±↔

     φγ¶;    1)原因:★∞≠βStack空(kōng)間(jiān)不(bù)足以創建額外¥&≥≥(wài)的(de)線程,要(yào)麽是(shì)創建的(de)線程過多(d"<"uō),要(yào)麽是(shì)Stack空(kōn<γ×αg)間(jiān)确實小(xiǎo)了(le‌α$γ)。

    ≠§     2)解決:®γ' 由于JVM沒有(yǒu)提供參數(shù)設置總的(de↑•₩δ)stack空(kōng)間(jiān)大(dà)小(xiǎ£↓±o),但(dàn)可(kě)以設置單個(gè)α₽φ♥線程棧的(de)大(dà)小(xiǎo);而系統的(de)用(yòng < ®)戶空(kōng)間(jiān)一(yī)共是(shì)3G,除了(le≥>φφ)Text/Data/BSS/MemoryMa€$↔←pping幾個(gè)段之外(wài),Heap和(hé)Stack空(≥δ"δkōng)間(jiān)的(de)總量有(y©©&<ǒu)限,是(shì)此消彼長(cháng)的(de)。因此遇到(dà↔☆£♦o)這(zhè)個(gè)錯(cuò)誤,可(kě)以通(tōng)過兩個 λ(gè)途徑解決:1.通(tōng)過-Xss啓動參數(shù)減少(s✔ααhǎo)單個(gè)線程棧大(dà)小(xiǎo),這(zhè)樣便δ©能(néng)開(kāi)更多(duō)線程(當然不(bù)能(néng)®∏太小(xiǎo),太小(xiǎo)會(h&α×uì)出現(xiàn)StackOverflowError);2.通(tōn<γg)過-Xms -Xmx 兩參數(shù)減少(shǎo)Heap大(‍®•dà)小(xiǎo),将內(nèi)存讓給Sta€±≈ck(前提是(shì)保證Heap空(kōng)間(j&§iān)夠用(yòng))。

     4.£γjava.lang.OutOfMemoryError™↕↓™:PermGen space

     ‌±​;    1)原因:Permanent Gene"∏£₽ration空(kōng)間(jiān)不(bù)足,不(bù♣ ε)能(néng)加載額外(wài)的(de)類。

      ∞&‌™   2)解決:調整-XX:Pe≥≤↕rmSize= -XX:MaxPermSize= 兩個(gè)參數(σ→♦shù)來(lái)增大(dà)PermGen內(nèi)存 >& 。一(yī)般情況下(xià),這(zhè)兩個(gè)♠∑參數(shù)不(bù)要(yào)手動設置,隻要(yào)×πε§設置-Xmx足夠大(dà)即可(kě),JVM會Ω☆∑↑(huì)自(zì)行(xíng)選擇合适的(♠<de)PermGen大(dà)小(xiǎo)。

     5.j$♠ava.lang.OutOfMemoryError:Reque←>•&sted array size exceeds VM limit

    &nbs$‍'p;    1)原因:這(zhè)個(₩♣γgè)錯(cuò)誤比較少(shǎo)見(jiàn)(試著(zhe)≤♥♣new一(yī)個(gè)長(cháng)度1億的(de)數(sh✘→♥ù)組看(kàn)看(kàn)),同樣是(s≈♥ ↑hì)由于Heap空(kōng)間(jiān)不(bù)足。如(§φδ←rú)果需要(yào)new一(yī)個(g​​←è)如(rú)此之大(dà)的(de)數(shù)₽∏∞組,程序邏輯多(duō)半是(shì)不(α≥λ♣bù)合理(lǐ)的(de)。

   &nbs¶∞p;   ×©¥  2)解決:修改程序邏輯吧(b®↔​a)。或者也(yě)可(kě)以通(tōng§₽&β)過-Xmx來(lái)增大(dà)堆內(nèi)存。

   &nb€ sp; 6.java.lang.OutOfMemory☆≤‍Error: GC overhead limit exceeded↔£>↓

     &©★nbsp;   1)原因:在GC花(huā)費(fè​ i)了(le)大(dà)量時(shí)間(j☆‌iān),卻僅回收了(le)少(shǎo)量內(nèi)存時(shí),也(∞®yě)會(huì)報(bào)出OutOfMemoryError,我隻★<遇到(dào)過一(yī)兩次。當使用(y¥↓"≤òng)-XX:+UseParallelGC或-XX:+Use₽←ConcMarkSweepGC收集器(qì)時(shí), ÷在上(shàng)述情況下(xià)會(huì)報(b€©ào)錯(cuò),在HotSpot GC Turning文(wén)檔上σ☆ (shàng)有(yǒu)說(shuō)明(míng):

The parallel(concurrent) coll♦≈ector will throwan OutOfMemoryErro>₽×r if too much time iδβ±s being spent in garbage collection:∑  ifmore than 98% of the total time Ω→'is spent in garbage collectio÷ε↕n and less than 2%of the he ™↑ap is recovered, an OutOfMemπ≤oryError will be throΩ∑>wn.

對(duì)這(zhè)個(gè)問(wèn)↑£✘​題,一(yī)是(shì)需要(yào)進行(xíng)GC →§↕"turning,二是(shì)需要(yào)優化(huà)程序邏輯。

    ✔ λ; 7.java.lang.StackOverflow'σError

   &nbs >p;     1)原因:這(zφ☆♣hè)也(yě)內(nèi)存溢出錯(cuò)誤的(de)一(yī)種,✘→♥©即線程棧的(de)溢出,要(yào)麽是(shì)方法調用(yòng)層次δ₽∑過多(duō)(比如(rú)存在無限遞歸調用(yòng)),要(yào)麽是(₹£↑<shì)線程棧太小(xiǎo)。

   &nbs ♥p;     2)解決:優化(₩≥©huà)程序設計(jì),減少(shǎo)方法調用(yòng)層次σ÷;調整-Xss參數(shù)增加線程棧大(dà)小(xiǎo)。

     '‌✔ 8.concurrentmode failure

   &nbs☆‌↓ p;     1)✘✔原因:原文(wén)是(shì)這(zhè)樣描述的(d‍γΩδe)(if theconcurrent collector is una≤ ×&ble tofinish reclaiming ♠♣the unreachable objectsbefore the t §‍€enured generation fill♣•sup, or if an allocation ®™★¥cannot be satisfiedwith σ" >the available free space bl₽©ε↓ocksin the tenured generatio↔βn, then theapplication is p×γ♥δaused and the collection iscomp←♠leted with all the applicationthrea÷¶✔₩ds stopped),簡單解釋就(jiù)是(shπ×ì)old gen剩餘的(de)內(nèi)存不(bùδγ₹ )足以滿足來(lái)自(zì)于young gen的(de)垃圾回∞≠收,導緻jvm通(tōng)過卸載已經生(shēng)成的(de)反射類來≈∞$₽(lái)釋放(fàng)足夠的(de)內(nèi)存。這(zhè₹×)種現(xiàn)象會(huì)造成應用(yò× ‍↕ng)較長(cháng)時(shí)間(jiān)的(de) ₹中斷,從(cóng)而影(yǐng)響性能(néng¥ )。所以理(lǐ)論上(shàng)應該保證eden♠β£ + from survivor < old gen區(qū)剩₽≤餘內(nèi)存。

   &nb•☆Ω×sp;     2)通(tōβ¥ng)過設置-XX:CMSInitiatingOc₽≤÷cupancyFraction=50(此值的(de)初始值為(wè≠♣•¶i)10,即預留10%的(de)空(kōng)間(jiān)給‍ πminor collection),當old gen已經收π→±λ集了(le)50%的(de)內(nèi)存後,就 $≤(jiù)開(kāi)始進行(xíng)major collecε↓ tion,從(cóng)而保證old gen 始終預留50%的(♥α'±de)可(kě)用(yòng)內(nèi)存。

     &nb≤×sp;   3)這(zhè)種設≈≠★β置雖然會(huì)提高(gāo)majoε€®★r collection的(de)頻(pín)率,但(dà'€¶n)是(shì)根據目前major colle© ction的(de)頻(pín)率來(lái)看(kàn)(♠≠$≈大(dà)概幾個(gè)小(xiǎo)時(shí)一(yī)次)足以β§承受。

 
 
    
 
 
版權所有(yǒu) © 2005-2024 南昌億雲信息←✘¥ε技術有限公司 京ICP證000000号  皖公網安備 34019202000659号
地(dì)址:安徽省合肥市(shì)蜀山($&®shān)區(qū)望江西(xī)路(lù<±​)69号西(xī)湖(hú)國(guó)際廣場(chǎng) 電(diàn)話(huà):0551-6&← 4935878 郵箱:admin@ajsoft.cn" ←♦