欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java服務(wù)器宕機(jī)的解決方法論

 更新時(shí)間:2021年08月04日 15:13:39   作者:JavaEdge.  
這篇文章主要介紹了Java服務(wù)器宕機(jī)的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

1 宕機(jī)概要

1.1 定義

向服務(wù)器的請求都沒有響應(yīng)或者響應(yīng)非常慢。

前端界面的崩潰并非宕機(jī)。

1.2 分類

進(jìn)程閃退

  • 內(nèi)部崩潰
  • 外部終止

線程鎖死或者無限等待

內(nèi)存溢出

下面分別進(jìn)行詳解

2 進(jìn)程閃退

2.1 內(nèi)部崩潰

JVM 發(fā)生內(nèi)部崩潰,必然會生成"hs_err_pid"開頭的文件。

下面講一種常見情況:

無法申請內(nèi)存,顯示commit_memory錯(cuò)誤

Current thread (0x00007f3e40013000):  JavaThread "Unknown thread" [_thread_in_vm, id=11408, stack(0x00007f3e49983000,0x00007f3e49a84000)]
 
Stack: [0x00007f3e49983000,0x00007f3e49a84000],  sp=0x00007f3e49a82360,  free space=1020k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x9a32da]  VMError::report_and_die()+0x2ea
V  [libjvm.so+0x497f7b]  report_vm_out_of_memory(char const*, int, unsigned long, char const*)+0x9b
V  [libjvm.so+0x81fcce]  os::Linux::commit_memory_impl(char*, unsigned long, bool)+0xfe
V  [libjvm.so+0x820219]  os::pd_commit_memory(char*, unsigned long, unsigned long, bool)+0x29
V  [libjvm.so+0x819faa]  os::commit_memory(char*, unsigned long, unsigned long, bool)+0x2a
V  [libjvm.so+0x99eae9]  VirtualSpace::expand_by(unsigned long, bool)+0x1c9
V  [libjvm.so+0x99ec6d]  VirtualSpace::initialize(ReservedSpace, unsigned long)+0xcd
V  [libjvm.so+0x57962f]  CardGeneration::CardGeneration(ReservedSpace, unsigned long, int, GenRemSet*)+0x11f
V  [libjvm.so+0x46ceed]  ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(ReservedSpace, unsigned long, int, CardTableRS*, bool, FreeBlockDictionary<FreeChunk>::DictionaryChoice)+0x5d
V  [libjvm.so+0x57a906]  GenerationSpec::init(ReservedSpace, int, GenRemSet*)+0x106
V  [libjvm.so+0x56afe4]  GenCollectedHeap::initialize()+0x344
V  [libjvm.so+0x9751aa]  Universe::initialize_heap()+0xca
V  [libjvm.so+0x976379]  universe_init()+0x79
V  [libjvm.so+0x5b1d25]  init_globals()+0x65
V  [libjvm.so+0x95dc6d]  Threads::create_vm(JavaVMInitArgs*, bool*)+0x1ed
V  [libjvm.so+0x639fe4]  JNI_CreateJavaVM+0x74

這一般是因?yàn)?Xmx 設(shè)置過大,超過系統(tǒng)可用內(nèi)存,JVM 申請內(nèi)存失敗。

比如服務(wù)器總內(nèi)存32G ,同時(shí)運(yùn)行多個(gè)程序,程序 A 配了20GXmx,其他程序也配了20G Xmx ,Linux的交換空間也沒有設(shè)置,這時(shí)候如果其他程序用滿20G內(nèi)存那么服務(wù)的可用內(nèi)存必然低于12G,這時(shí)如果Tomcat需要大于12G的內(nèi)存就很容易發(fā)生該錯(cuò)誤,直接宕機(jī)!

解決方案

  • 減少Xmx值使得所有的綜合不超過服務(wù)器物理內(nèi)存
  • 調(diào)整 Xms=Xmx
  • 服務(wù)器不要運(yùn)行其他不必要的東西
  • 配置一部分swap空間(虛擬內(nèi)存)

2.2 外部終止

如果找不到"hs_err_pid"開頭的文件,那么這個(gè)進(jìn)程的閃退必然是被從外部終止的。

2.2.1 OOMKiller

java長期內(nèi)存占用過高,系統(tǒng)需要內(nèi)存使用的時(shí)候沒有內(nèi)存,Linux的oomkiller機(jī)制會干掉最低優(yōu)先級的內(nèi)存

檢查 /var/logs/message , /var/logs/dmesg或者對應(yīng)日期文件,看看有沒有類似下面的內(nèi)容,日志有時(shí)間可以判斷

2.2.2 SSH注銷

檢查/var/log/auth.log,/var/log/secure或者對應(yīng)日期的文件,檢查宕機(jī)的時(shí)間點(diǎn)有沒有

時(shí)間吻合,那么宕機(jī)原因即可確認(rèn)。

解決方案

使用nohup命令在后臺運(yùn)行啟動(dòng)程序,檢查ssh注銷原因

2.2.3 其他人為因素

不是很好判斷,需要給shell加上操作記錄

3 線程鎖死/無限等待

表現(xiàn)

系統(tǒng)無法訪問時(shí),當(dāng)前cpu占用非常低

使用 jstack命令輸出線程堆棧即可

jstack pid >> 1.txt
or
jstack -F pid >> 1.txt

都行,或者用jprofiler工具看堆棧,或者其他任何可以拿到堆棧的工具都可以, java的堆棧就是java方法調(diào)用的路徑,可以定位一些簡單的問題

4 內(nèi)存溢出

現(xiàn)象

CPU全部占滿,內(nèi)存達(dá)到配置Xmx最大值

4.1 CPU占滿緣由

并不是 CPU 不夠用,而是涉及到JVM的GC 機(jī)制,大部分情況來說CPU都是過剩的

JVM 使用GC的方法來回收沒有被引用的內(nèi)存塊,在當(dāng)前的回收機(jī)制中,回收器是并發(fā)進(jìn)行的,回收的線程個(gè)數(shù)有一個(gè)公式:

當(dāng)CPU核心數(shù)

小于8

  • 1個(gè)核心對應(yīng)一個(gè)gc線程

大于8

  • gc的線程數(shù)= 8 + ((N - 8) * 5/8)

N代表核心的數(shù)量,這是默認(rèn)的gc線程創(chuàng)建公式

threads = N <= 8 ? N : (8 + ((N - 8) * 5/8))

當(dāng)然也可以通過參數(shù) -XX:ParallelCMSThreads=20 來配置 GC 線程數(shù),就不會使用默認(rèn)的設(shè)置,默認(rèn)情況下不要調(diào)整,因?yàn)檎{(diào)了也沒什么卵用,最多在宕機(jī)的時(shí)候cpu占用按照你設(shè)定的值來。

當(dāng)發(fā)生內(nèi)存溢出的時(shí)候,或者快要內(nèi)存溢出的時(shí)候,不一定是內(nèi)存溢出,JVM 發(fā)現(xiàn)內(nèi)存不夠了,就會 GC,所有線程開始工作,暫停 JVM 運(yùn)行,開始回收,如果回收到內(nèi)存了,ok,jvm可以正確繼續(xù)執(zhí)行,

這也就是為什么有時(shí)候配置內(nèi)存溢出的參數(shù)沒有自動(dòng)生成dump的原因,因?yàn)樗苓\(yùn)行,但是比較慢,所以沒有OOM,就不會生成dump,

如果沒有回收到什么內(nèi)存,gc會循環(huán)持續(xù)執(zhí)行,這就導(dǎo)致了cpu全部占滿的現(xiàn)象,所以說內(nèi)存溢出的時(shí)候,一定伴隨cpu占滿(按照設(shè)置或者公式計(jì)算的線程量)

4.2 JVM內(nèi)存分配機(jī)制

在說說JVM怎么分配內(nèi)存的,大家都知道給客戶配置Xmx參數(shù)和xms參數(shù),Xmx代表的是最大堆內(nèi)存,xms代表的是最小堆內(nèi)存,至于permsize就和這些都沒有關(guān)系,不能算在內(nèi)存溢出,遇到拋錯(cuò)outofmemory permsize什么的調(diào)大就行了

permsize是一個(gè)被jvm也拋棄的參數(shù)只存在1.7之前的jdk中,是用來保存java的class等內(nèi)容的存儲空間,1.8被metaspace替代

這個(gè)內(nèi)存怎么不回收的啊,一問都是在任務(wù)管理器看的!這個(gè)地方是看不到內(nèi)存回收的,或者說他也會回收,但是可能要等個(gè)好幾天才會回收一次,可以忽略這種機(jī)制的存在

形而上學(xué)

WC 論

如果把內(nèi)存比喻成茅坑,操作系統(tǒng)64g內(nèi)存就是一共64個(gè)茅坑,那么JVM的內(nèi)存回收相當(dāng)于茅坑調(diào)度系統(tǒng),每個(gè)gc線程相當(dāng)于調(diào)度系統(tǒng)派出去的茅坑檢查員,給jvm設(shè)置了 Xms=2g, Xmx=32g,那么程序啟動(dòng),jvm直接占了兩個(gè)茅坑,任務(wù)管理器看到內(nèi)存占用2g,即使沒人上廁所,JVM也不會把坑還給操作系統(tǒng)。

假設(shè)一個(gè)人上廁所10秒,一開始的時(shí)候 20秒有一個(gè)人來上廁所,那么 jvm通過茅坑檢查員發(fā)現(xiàn)哎兩個(gè)坑總有一個(gè)是空的,維持茅坑數(shù)量不變,內(nèi)存的占用一直是2g,過了些時(shí)候,來的人開始增多了,變成5秒有一個(gè)人來上廁所,茅坑檢查員向JVM匯報(bào)有人開始有排隊(duì)了,兩個(gè)坑位很緊張,不行要多弄幾個(gè)坑才行,于是,jvm向系統(tǒng)又申請了兩個(gè)坑,任務(wù)管理器可以看到內(nèi)存占用變成了4個(gè)G,這時(shí)候又突然發(fā)生壓力增大,變成了1秒來一個(gè)人,4個(gè)坑肯定不夠啊,于是jvm又把內(nèi)存擴(kuò)容到10-11g,現(xiàn)在夠用了,任務(wù)管理器會看到內(nèi)存一直維持在10-11g,終于大家都上完廁所了,沒人排隊(duì)了,茅坑都空出來了。

但是,jvm是個(gè)霸道總裁,被他占的東西,除非死不然不會吐出來的,所以任務(wù)管理器里面看到內(nèi)存還是10-11g不會降低,除非jvm死了,實(shí)際沒有任何內(nèi)存占用(所以不要再說內(nèi)存不回收的問題,這個(gè)內(nèi)存的回收不回收和宕機(jī)是沒有直接關(guān)系的)

如果這時(shí)候突然一下子來了很多很多人,比如一下子來了64個(gè)人要上廁所,這時(shí)候會怎樣了,JVM把他的所有的茅坑檢查員都派出去檢查啊,然后發(fā)現(xiàn)完蛋了茅坑不夠用啊,申請到32個(gè)都不夠用啊,于是jvm的特派茅坑檢查員就一個(gè)坑一個(gè)坑的拍,一個(gè)坑一個(gè)坑的催,結(jié)果呢,檢查員在催,大家就拉不出來了,上廁所的時(shí)間無限期延長,外面的人要進(jìn)去,里面的人出不來,BOOM,廁所就不響應(yīng)了,后面來的人都拉褲子了。

怎么解決?

  • 換個(gè)茅坑管理員,更好的調(diào)度茅坑檢查員和分配茅坑,這就有了G1回收器 ,茅坑越多效果越好,目前JDK情況內(nèi)存大于10G的情況G1的效果好于CMS,低于10G的情況下不如CMS
  • 從源頭控制人員,不要一下子來這么多人(申請內(nèi)存),也就是常見的不要讓業(yè)務(wù)查大量數(shù)據(jù)占內(nèi)存。

而上面講的線程鎖死的情況要做類比的話,就是32個(gè)坑唄32個(gè)人占了,還死活不肯出來,導(dǎo)致后面排隊(duì)的人失去響應(yīng)了。

沒有味道的比喻

解釋一下java的面向?qū)ο蠛蛯ο笠?

一棟大樓,10層共1000個(gè)工位 (類比物理內(nèi)存)。

包給一個(gè)二房東 中介公司Z (jvm)。

中介公司和大樓物業(yè)談好彈性繳費(fèi),租多少出去收多少錢。

Z公司先一下租300個(gè)位置 (類比Xms)省錢,

Z公司和物業(yè)談好最多租600個(gè)位置(類比Xmx)。

Z公司找到了公司A(200人)來這里 就占用了200個(gè)工位 (類比一次數(shù)據(jù)查詢)。

公司A是一個(gè)大的對象,每個(gè)人類比最小的單元格,每個(gè)小團(tuán)隊(duì)也是一個(gè)對象,個(gè)人被小團(tuán)隊(duì)引用,小團(tuán)隊(duì)又被更上級的比如產(chǎn)品,比如大技術(shù)支持大團(tuán)隊(duì)引用,大團(tuán)隊(duì)又被公司引用,最終公司這個(gè)大對象占用了200工位,類比下來200個(gè)工位內(nèi)存不釋放的根就是這個(gè)公司在這兒上班。

這時(shí)候公司A倒閉了,200個(gè)工位就空出來了(內(nèi)存釋放)。

  • 內(nèi)存溢出宕機(jī)是什么情況呢?
  • 找Z公司租工位的公司,總工位超過了600,總不能坐大腿上上班啊,于是物業(yè)不會給Z工位的,合同寫的好好的,Z公司不滿足客戶需求,運(yùn)作不起來破產(chǎn)倒閉。
  • 經(jīng)常遇到的申請內(nèi)存失敗的崩潰是什么情況?
  • 物業(yè)是個(gè)滑頭,不止找了Z公司一家中介,還有Y公司也是做中介的(類比兩個(gè)JVM)。都承諾Z和Y公司都是最多可以租600個(gè)位置。初始都租的300個(gè)位置,大家相處融洽,隨著公司不停入住,矛盾出現(xiàn)了:
  • Y公司效益比較好,先找了公司,已經(jīng)占了600位置;
  • 這時(shí)候Z公司的效益也上來了,也要增加工位 (類比申請內(nèi)存),這時(shí)候物業(yè)根本沒有位置能給他。于是Z公司運(yùn)轉(zhuǎn)不下去,破產(chǎn)倒閉

5 總結(jié)

宕機(jī)分析的目的就是要找到占用內(nèi)存的東西,把他找出來,找出他的原因,然后把它改掉。JVM的內(nèi)存對象分配相當(dāng)于一顆樹,所有的對象都被層層引用,直到GCRoot根節(jié)點(diǎn),如果沒有根節(jié)點(diǎn)的引用,這個(gè)對象是完全可以直接釋放掉的,大部分也是因?yàn)間cRoot存在的對象過多導(dǎo)致的宕機(jī),當(dāng)然也不排除可以使用已經(jīng)回收的對象來分析,由于生成dump的時(shí)間不精確,可能他生成的時(shí)候 ,對應(yīng)的大組件已經(jīng)回收了,但是jvm緩過來還需要一些時(shí)間,所以還是處于大量gc的狀態(tài),這時(shí)候只能通過對于引用的檢索找到最多的引用對象來進(jìn)行分析。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論