在docker中使用java的內存情況
前言
微服務和docker的結合應該是現在服務端的主流技術,隨着springboot的出現,有很多公司已經把微服務遷移到了docker容器中,我們也不甘寂寞,也嘗試了一把新技術,把以前的整體服務進行拆分以后,也全部上到了docker容器中。
問題
很久之前,業務部門利用springboot開發好一個app以后,就可以通過java -jar
的命令把程序丟給docker,然后在容器中啟動起來,也不管到底系統給這個應用分配了多少內存。
后來由於java默認使用的內存是docker實體機器1/4的內存,導致部署了很多應用以后,經常出現內存不足的情況,然后公司要求應用在啟動的時候通過jvm的啟動參數來限制java使用的內存來緩解內存消耗過快的問題。
再后來,我們的docker平台進行了升級, 有了可以讓應用限制cpu個數和mem大小的參數設置,后面應用方把app的 -Xmx
和docker的內存大小設置成同樣大小, 比如2g。后面發現跑了一段時間以后,應用經常出現oom的情況,而被殺掉。
因為java使用的內存不僅僅是 -Xmx
設置的大小, -Xmx
設置的大小只是java進程堆的最大占用內存,
原因
為什么會出現上面這個問題呢?通過監控系統可以知道,docker獲得的mem_usage的大小是從外部得到的java進程的內存大小,不僅僅是 -Xmx
設置的大小,如果 -Xmx
和docker分配的內存一致的話,由於java應用其他的地方還要占用不少的內存,導致還沒有到達 -Xmx
的時候就沒有可以用的內存了,所以被docker容器給干掉了,從而出現了oom的情況。
那么java程序啟動的時候需要哪些方面的內存呢?
- java程序的堆內存,最大就是
-Xmx
設置的這個值 - Garbage collection在垃圾回收的時候使用的內存
- JIT optimization使用的內存
- java程序的Off-heap所使用的內存
- java程序的Metaspace所使用的內存
- JNI Code所占用的內存
- jvm啟動的時候所占用的內存。
如何大體估算java進程使用的內存呢?
Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]
上面的公式大體得到了內存的占用,但是不是全部占用,網上有一些人做了一些試驗,有兩篇比較好的介紹文章:
https://plumbr.eu/blog/memory-leaks/why-does-my-java-process-consume-more-memory-than-xmx
和
http://trustmeiamadeveloper.com/2016/03/18/where-is-my-memory-java/
所以猜測在設置jvm啟動參數的時候 -Xmx
的這個值一般要小於docker限制內存數,個人覺得 -Xmx
:docker
的比例為 4/5 - 3/4
,
目前正在試驗和觀察,這里僅僅保存一下記錄,以免忘記。