導讀java
JVM是Java Virtual Machine的縮寫,中文名爲Java虛擬機。它是一種用於計算設備的規範,是一個虛構出來的計算機,主要經過在實際的計算機上仿真模擬各類計算機功能來實現的。在實際運用過程當中,易觀技術人員注意到一臺開發機上各個微服務進程佔用內存很高,隨即使展開了調查......linux
現象:前段時間發現某臺開發機上各個微服務進程佔用內存很高,這裏記錄下解決思路,僅供參考。程序員
VIRT和RES都很高......spring
以其中某個進程爲例(進程啓動日期爲8月9日,排查時候的時間是8月10日10:54:58,也就是說該進程運行時間應該不會超過48小時)sql
top命令查看該進程佔用內存狀況(能夠看到此進程已經佔用2.7G物理內存)springboot
爲了排除掉是由於中途有壓力測試的嫌疑,將此服務進行了重啓,可是剛起的進程(19146),多線程
佔內存狀況RES:1.8G, VIRT:33.4G …架構
JVM進程動不動就是2G以上的內存,然而開發環境並沒什麼業務請求,誰是罪魁禍首 ?併發
解決問題以前,先複習下幾個基礎知識。
1. 什麼是RES和VIRT?jvm
(1)進程當前使用的內存大小,但不包括swap out
(2)包含其餘進程的共享
(3)若是申請100m的內存,實際使用10m,它只增加10m,與VIRT相反
(4)關於庫佔用內存的狀況,它只統計加載的庫文件所佔內存大小
RES = CODE + DATA
(1)進程「須要的」虛擬內存大小,包括進程使用的庫、代碼、數據等
(2)假如進程申請100m的內存,但實際只使用了10m,那麼它會增加100m,而不是實際的使用量
VIRT = SWAP + RES
2. Linux與進程內存模型
3. JVM內存模型(1.7與1.8之間的區別)
因此JVM進程內存大小大體爲:
非heap(非heap=元空間+棧內存+…)+heap+JVM進程運行所需內存+其餘數據
那麼會是jvm內存泄漏引發的嗎?
能夠看到,堆內存一切正常(dump會引發FGC,但並不影響此結論)
那麼多是SpringBoot的緣由嗎?
爲了驗證此問題,經過部署系統在開發機上起了1個沒有任何業務代碼的springboot進程,僅僅是引入註冊中心
查看此進程內存佔用狀況:
明顯已經設置了Xmx爲512MB,雖然Xmx不等於最終JVM所佔總內存,但至少也不會誤差太多; 那麼使用jmap命令查看當前jvm堆內存配置和使用狀況(下面的圖2是在圖1現場5分鐘以後截取的)
因此從2次的jmap結果中,能夠得出如下幾個結論:
元空間(20.79MB)+ eden(834MB)+年老代(21MB)+線程棧(38*1024KB)+JVM進程自己運行內存+ NIO的DirectBuffer +JIT+JNI+…≈top(Res) 1.1G
當前jvm線程數統計:jstack 7311 |grep ‘tid’|wc –l (linux 64位系統中jvm線程默認棧大小爲1MB)
Xmx設置爲什麼未生效?
查看部署系統的啓動腳本,發現啓動方式爲:Java –jar $jar_file –Xms512m –Xmx1024m
正確的Java命令:
java [ options ] class [ arguments ]
java [ options ] -jar file.jar [ arguments ]
其實到這裏,也找到了此問題緣由所在,Java –jar $jar_file –Xms512m –Xmx1024m被JVM解釋成了程序的參數。
手動執行: java –Xms512m –Xmx1024m –jar ems-client-1.0.jar
至此,RES太高的問題已解決,可是VIRT的問題還在
使用系統命令pmap -x 3516查看進程的內存映射狀況,會發現大量的64MB內存塊存在;統計了下,大概有50多個65404+132=65536,正好是64MB,算起來大約3個多G
因而Google之,發現大體的緣由是從glibc2.11版本開始,linux爲了解決多線程下內存分配競爭而引發的性能問題,加強了動態內存分配行爲,使用了一種叫作arena的memory pool,在64位系統下面缺省配置是一個arena大小爲64M,一個進程能夠最多有cpu cores * 8個arena。假設機器是8核的,那麼最多能夠有8 * 8 = 64個arena,也就是會使用64 * 64 = 4096M內存。
然而咱們能夠經過設置系統環境變量來改變arena的數量:
export MALLOC_ARENA_MAX=8(通常建議配置程序cpu核數)
配置環境變量使其生效,再重啓該jvm進程,VIRT比以前少了快2個G:
總結:這裏只是提供一種解決問題的思路,僅供參考;通常咱們遇到問題以後, 首先想到的是否是程序有問題,而後跟蹤了好久仍是未找到問題根本緣由;幾經周折, 才發現問題是出如今最容易被咱們忽視的地方(好比這裏的腳本命令問題)!
歡迎工做一到五年的Java工程師朋友們加入Java程序員開發: 854393687
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用本身每一分每一秒的時間來學習提高本身,不要再用"沒有時間「來掩飾本身思想上的懶惰!趁年輕,使勁拼,給將來的本身一個交代!