某天忽然收到線上應用的gc時間過長的告警,剛開始只有一臺機器偶爾報一下,後續其餘機器也紛紛告警,具體告警的閾值是應用10分鐘內ygc的總時長達到了6.6s。javascript
-XX:+PrintReferenceGC
參數,通過一段時間觀察,應用重啓後,觀察了一段時間,發現gc日誌中JNI Weak Reference處理時長變得愈來愈長。並且佔用整個ygc時長的大部分。jdk.nashorn.internal.ir.IdenNode
經過引用鏈找到可疑的js腳本對應的String
,嘗試了不少次發現都失敗了。主要自己對jdk.nashorn
包下類不是很熟悉,再加上引用鏈都比較長,因此找了好久都沒有找到這個類和腳本的應用關係。String
對象存在,String
底層採用char[]
來存儲字符。因此直接找char[]
實例中內容爲js腳本的,可是這裏又遇到一個問題,看上面的dump文件圖,會發現char[]
實例數當前內存有100w+,這裏就抓住了部分js腳本長度比較長的一個特色。直接根據size正序排列,長度前10的字符串,就直接就找到了一個腳本,順着引用鏈會輕易發現,js腳本的內容都是保存在Source$RawData
對象中的,以下圖
Classes
欄目,直接搜索Source$RawData
,能夠看到有241個實例,以下圖
,這241個,而後找了出現頻率比較高的幾個js腳本,而後看了對應腳本的調用方式,發現其中一個腳本每次執行都是經過ScriptEngine.eval
這種方式來執行,就形成了``JNIHandleBlock```,不斷增加的問題,最終致使ygc時,處理JNI Weak Reference的時間愈來愈長。eval
方法,換成Bindings的方式調用。-Xms4000m -Xmx4000m -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:MaxDirectMemorySize=512m -XX:+UseCMSInitiatingOccupancyOnly -XX:SurvivorRatio=8 -XX:+ExplicitGCInvokesConcurrent -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=512m -XX:-OmitStackTraceInFastThrow -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/www/logs/gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/www/logs -Djava.io.tmpdir=/var/www/tmp -Dio.netty.availableProcessors=4 -XX:ParallelGCThreads=4 -Dpinpoint.applicationName=crawler-worker.product-bank
這樣,其中-Xms4000m
是初始化堆大小,-Xmx4000m
是最大堆大小,而後重啓應用,重啓後,就收到ygc頻繁的告警,而後用jstat -gc pid 3000
看了下,發現了奇怪的地方(以下圖)
年輕代總容量才300多m(S0C+S1C+EC),而年老大總容量(OC)有3700多m,這種狀況就直接致使了,直接分配對象空間的eden區域很容易就佔滿了,而直接觸發ygc,而致使這個問題的緣由呢,是忘記配置-Xmn1024m
參數致使,這個參數就是制定年輕代的大小,這裏的大小配置成整個堆的1/4至1/2都是合理的,加上這個參數後,剛啓動應用就ygc時間過長的問題就獲得瞭解決。版權聲明
做者:wycm
出處:juejin.im/post/5c8a5a…
您的支持是對博主最大的鼓勵,感謝您的認真閱讀。 本文版權歸做者全部,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。 java