這陣子都在搞DevSecOps,實作上的一部分重點就是將安全測試導入CI/CD當中。
那SAST(靜態應用程式安全測試)的部分我是使用知名的開源原始碼掃描平台SonarQube,
不過在整合到Jenkins的時候發生了一些小問題,主要應該是 SonarQube 安裝了 Findbugs 插件,
而 Findbugs 由於太過吃記憶體,一值導致產生了記憶體的問題。
不過由於這算是很特別的個案,之後若有機會再針對這個個案寫一篇Debug文章,
這邊就只是先記錄,Debug 的過程當中有需要修改到 JVM 的記憶體參數,
所以需要對參數有些基本的理解,方便未來遇到跟 JVM 相關的問題可以回來看看自己的筆記。
問題
遇到的問題可能會像以下
java.lang.OutOfMemoryError: Java heap space
java.lang.OutOfMemoryError: GC overhead limit exceeded
如果是 java.lang.OutOfMemoryError 的問題
常見的可能是以下幾種情況
(1) 記憶體中載入的資料量過於龐大,如一次從資料庫取出過多資料
(2) 集合類中有對物件的引用,使用完後未清空,使得JVM不能回收
(3) 程式碼中存在死迴圈或迴圈產生過多重複的物件實體
(4) 使用的第三方軟體中的BUG
(5) 啟動引數記憶體值設定的過小
那這邊如果是JVM記憶體值的設定過小,可以嘗試修改參數來調整加大JVM記憶體空間
那有兩大重點
1.知道指令 => 當然要先知道怎麼下指令呀,不然怎麼調整
2.知道參數意思 => 如果你不知道參數意思,亂設定很可能沒辦法解決問題
舉個例子,我當時遇到這個問題,看到網路上有解法寫說輸入以下這串指令
export SONAR_SCANNER_OPTS="-Xmx3062m -XX:MaxPermSize=512m -XX:ReservedCodeCacheSize=128m"
後來就照說下了這個指令,問題當然沒有解決。
而且後來查了一下參數的意思,發現我預設的記憶體根本就比這串指令還要大,
所以下了之後根本也就不會加大我的JVM記憶體最大值。
JVM參數意義
這邊整理一下常見的參數:
-Xms (initial heap size):JVM初始分配的堆記憶體,預設會是實體記憶體的1/64
-Xmx (maximum heap size):JVM最大允許分配的堆記憶體,預設會是實體記憶體的1/4
-XX:PermSize:JVM初始分配的非堆記憶體, 預設會是實體記憶體的1/64
-XX:MaxPermSize: JVM最大允許分配的非堆記憶體, 預設會是實體記憶體的1/4
關於預設記憶體大小可以參考官方文件
https://docs.oracle.com/javase/6/docs/technotes/guides/vm/gc-ergonomics.html
( XX:PermSize 跟 XX:MaxPermSize 的預設值大小我比較不確定,沒看到官方文件。都是聽網路說法)
以上四個參數,其實看可看出,主要就是分成堆記憶體與非推記憶體
堆(Heap)和非堆(Non-heap)記憶體,下面這張圖我覺得可以滿好的幫助理解
接著就來說如何下指令還有一些注意事項
範例一
範例一:
export JAVA_OPTS="-Xms1024m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=1024m"
export 就是去修改環境變數,這邊修改的變數是 JAVA_OPTS,
實際上要修改甚麼環境變數要看你遇到的案例,視情況而定,
還有就是稍微注意 export,只再當次登入的情況下有效,如果重新開機就會消失了。
你可以利用下面的指令來稍微確認先前的 JAVA_OPTS 是否已經有設定。
echo $JAVA_OPTS
這邊的指令設定了四個參數 -Xms1024m -Xmx1024m -XX:PermSize=512m -XX:MaxPermSize=1024m
參數意思上面也都提到過了,參數後面帶的就是要調整的大小,
-Xms1024m 表示 初始分配的堆記憶體為 1024 MB的記憶體
-Xmx1024m 表示 最大允許分配的堆記憶體為 1024 MB的記憶體
-XX:PermSize=512m 表示 初始分配的非堆記憶體為 512 MB的記憶體
-XX:MaxPermSize=1024m 表示 最大允許分配的非堆記憶體為 1024 MB的記憶體
範例二
範例二:
export SONAR_SCANNER_OPTS="-Xms32g -Xmx32g -XX:PermSize=1g -XX:MaxPermSize=16g -XX:ReservedCodeCacheSize=512m"
範例二可以注意到這邊修改的環境變數就不是 JAVA_OPTS,而是 SONAR_SCANNER_OPTS,是由於我的需要所設定。
再來是可以注意到參數調整容量的部分不是用m而是改成g了,可以直接換單位來指定GB
-Xms32g 表示 初始分配的堆記憶體為 32 GB的記憶體
-Xmx32g 表示 最大允許分配的堆記憶體為 32 GB的記憶體
-XX:PermSize=1g 表示 初始分配的非堆記憶體為 1 GB的記憶體
-XX:MaxPermSize=16g 表示 最大允許分配的非堆記憶體為 16 GB的記憶體
-XX:ReservedCodeCacheSize=512m 表示 保留的程式碼快取空間為 512 MB
注意事項
然後有幾點注意事項:
1.-Xms 的值不可大於 -Xmx,還有 -XX:PermSize 的值不可大於 -XX:MaxPermSize
2.-Xmx 和 -XX:MaxPermSize 的總和不可超過實體記憶體的最大值
3.一般建議 -Xms 與 -Xmx 的值設定為相同 (官方也是這樣建議)
Oracle recommends that -Xmn and -Xmx be set to the same value. This eliminates potentially costly heap reallocations, and can reduce the amount of heap fragmentation that can occur
補充
此篇筆記,之後若有知識增長或是觀念修正,都會滾動式更新。
範例中的指令單純是參考,並不建議在不明白意義的情況下複製貼上到自己的機器中。
若有大神要糾正或是覺得可以補充的也歡迎留言、寄信、私訊給我!(在臉書粉專私訊會比較快回)
參考來源
https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/313033/
https://www.gushiciku.cn/pl/poUC/zh-tw