當Java虛擬機遇上Linux Arena內(nèi)存池
2017-10-27 00:06 來源:數(shù)據(jù)和云
<article class="article" id="mp-editor">
作者簡介
劉韜踢涌,云和恩墨中間件服務交付團隊專家
Java開發(fā)出身稚新,10年WebLogic相關(guān)開發(fā)尖坤、運維工作經(jīng)驗,熟悉SOA井赌、現(xiàn)代業(yè)務系統(tǒng)架構(gòu)中各層組件,尤其擅長故障處理拦宣、性能優(yōu)化等工作网缝。
故障案例一
系統(tǒng)環(huán)境:
RHEL 6.8 64-bit(glibc 2.12)、Sun JDK 6u45 64-bit疫稿、WLS 10.3.6
故障現(xiàn)象:
這里引用一下客戶當時發(fā)郵件時提出的問題描述吧培他。
下面pid 6287 weblogic進程占用7.6G的物理內(nèi)存鹃两,之前只占用5G內(nèi)存。我發(fā)現(xiàn)只有系統(tǒng)有空余的內(nèi)存舀凛,就會被java給吃掉俊扳,為什么內(nèi)存占用越來越多?
通過jmap -histo:live 6287 查看內(nèi)存只占用800多MB猛遍。
Total 12415620 891690640
image此時馋记,操作系統(tǒng)內(nèi)存幾乎耗盡,而且用了很多Swap交換分區(qū)內(nèi)存懊烤,系統(tǒng)性能并不是很好梯醒。
故障分析:
剛開始看到這個問題時,首先考慮可能是Native Memory Leak或JDK的Bug腌紧,然后看了下那些WebLogic進程的命令行參數(shù):
/data/jdk1.6.0_45/bin/java -server -Xms2560m -Xmx2560m .....
從JDK入手
一看茸习,已經(jīng)是6u45了,Sun Java SE Public版的最終版本了寄啼,找來找去也沒找到匹配的Bug(當時還真找到一個看著很像的逮光,JDK-2172773 : JVM sometimes would suddenly consume significant amount of memory,但人家是在6u14b01墩划、5u16rev這兩個版本開始涕刚,都已經(jīng)修復了),看來不能從JDK Bug這個方向入手分析了乙帮。
從Native Memory Leak入手
但是這個JDK版本也比較尷尬杜漠,沒有提供Native Memory Trace的功能參數(shù)或命令支持(from 7u40版本開始提供),要知道Sun Java SE內(nèi)部的內(nèi)存區(qū)域很復雜察净,常見或不常見的很多區(qū)域驾茴,下面拿JDK 8版本(6版本大同小異)的內(nèi)存區(qū)域為例展示一下:
(圖片來源于SAP公司某技術(shù)專家在OOW演講時的一篇文章)
沒有直接的診斷工具的情況下,只能通過一些操作系統(tǒng)命令對這些RES氢卡、VIRT內(nèi)存占用都高的JVM進程的內(nèi)存使用輸出結(jié)果做比較锈至,以從中找出一些蛛絲馬跡。最終译秦,確定使用pmap這個命令(程序)峡捡,結(jié)果看到如下的輸出結(jié)果:
這里發(fā)現(xiàn)一個規(guī)律,65484 + 52 = 65536 KB, 65420 + 116 = 65536 KB, 65036 + 500 = 65536 KB .... 筑悴,進程內(nèi)有大量的這種64MB大小的連續(xù)內(nèi)存塊们拙。
然后,就是需要知道這是什么東東阁吝,Google一把砚婆,得知anon是Anonymous memory段的縮寫。
Anonymous memory is a memory mapping with no file or device backing it.
This is how programs allocate memory from the operating system for use
by things like the stack and heap.
Anonymous memory的使用會使虛擬內(nèi)存(VIRT)突勇、物理內(nèi)存(RSS)使用率上升装盯。
而且坷虑,找到兩篇講的很清晰的文檔了:
JAVA 進程在64位LINUX下占用巨大內(nèi)存的分析
文章鏈接 :https://blog.chou.it/2014/03/java-consume-huge-memory-on-64bit-linux
Linux glibc >= 2.11 (RHEL 6) malloc may show excessive virtual memory usage
那這個問題就是Arena內(nèi)存池數(shù)太多,且分配使用的內(nèi)存較多验夯,不斷上漲猖吴,導致的WebLogic/Java虛擬機進程RES、VIRT內(nèi)存使用超高挥转。
這部分內(nèi)容是有一定的原理的海蔽,和故障二里面的理論集中在一起,放在文章下方說明了绑谣。
解決辦法:
直接想到的解決思路就是限制Arena內(nèi)存池的個數(shù)党窜。考慮到Arena內(nèi)存池的主要是用來提高glibc內(nèi)存分配性能的借宵,而且根據(jù)Hadoop幌衣、Redis等產(chǎn)品的最佳實踐建議,嘗試設(shè)置MALLOC_ARENA_MAX環(huán)境變量值為4:
export MALLOC_ARENA_MAX=4
設(shè)置完重啟WebLogic壤玫,然而意外的是豁护,設(shè)置完以后Java虛擬機/WebLogic進程RES、VIRT內(nèi)存使用依然很高:
后來我查到glibc 2.12版本有幾個Arena內(nèi)存管理的Bug欲间,可能導致參數(shù)設(shè)置不生效或生效后內(nèi)存繼續(xù)往上漲:
Bug 799327 - MALLOC_ARENA_MAX=1 does not work in RHEL 6.2(glibc 2.12)
Bug 20425 - unbalanced and poor utilization of memory in glibc arenas may cause memory bloat and subsequent OOM
Bug 11261 - malloc uses excessive memory for multi-threaded applications
然后楚里,我們考慮到將MALLOC_ARENA_MAX設(shè)置為4已經(jīng)影響了一些Arena內(nèi)存池管理上的一些性能,要繼續(xù)使用MALLOC_ARENA_MAX參數(shù)猎贴,就需要升級glibc的版本班缎,升級完還不確定高版本的glibc與其他包兼容性上有什么影響,畢竟是操作系統(tǒng)底層的包了她渴,所以就直接使用了Google的tcmalloc替代操作系統(tǒng)自帶的glibc管理內(nèi)存达址。有資料顯示,使用tcmalloc以后趁耗,Web Server的吞吐量得以提升(先嘗試的jemalloc沉唠,但是啟動后會影響操作系統(tǒng)命令的執(zhí)行,所以苛败,就用了tcmalloc):
替換為tcmalloc以后右冻,WebLogic/Java虛擬機進程使用的RES、VIRT內(nèi)存明顯下降到合理值著拭,問題得以解決。
故障案例二
系統(tǒng)環(huán)境:
RHEL 6.5 64-bit(glibc 2.12)牍帚、Sun JDK 5u22 32-bit儡遮、WLS 10.0.2
故障現(xiàn)象:
客戶核心系統(tǒng)由于業(yè)務的需要,新加了一個節(jié)點暗赶,沿用原先的相同的操作系統(tǒng)鄙币、WebLogic肃叶、JDK版本,并且保證所有WebLogic參數(shù)配置都是相同的情況下十嘿,經(jīng)常出現(xiàn)Java虛擬機Crash的情況:
file hs_err_pid28384.log :
An unexpected error has been detected by HotSpot Virtual Machine:
SIGSEGV (0xb) at pc=0xf6f8405d, pid=28384, tid=815790960
Java VM: Java HotSpot(TM) Server VM (1.5.0_22-b03 mixed mode)
Problematic frame:
V [libjvm.so+0x24405d]
......
故障分析:
由于這是32-bit的JDK因惭,那就是Native Memory使用過高,超過了尋址空間的限制(4G绩衷,默認User Space : Kernel Space = 3 : 1蹦魔,但在目前的Linux內(nèi)核版本中,大多數(shù)32-bit的進程運行在64-bit操作系統(tǒng)上咳燕,幾乎都可以用到所有的4G用戶空間)。
在做分析之前招盲,為擴大Native Memory空間,我降低了Java Heap Size(-Xms曹货、-Xmx)和 Perm Size(-XX:PermSize咆繁、-XX:MaxPermSize)的值玩般,以此來放緩Native Memory上漲的形勢(客戶不同意使用64-bit JDK)。
接下來壤短,就是分析什么東東造成Native Memory使用持續(xù)上漲了。這里慨仿,還是用了pmap去看下Native Memory的使用和變化:
這里也看到了許多984 + 40 = 1024 KB, 1012 + 12 = 1024 KB, 988 + 36 = 1024 KB .... ,進程內(nèi)有大量的這種1MB大小的連續(xù)內(nèi)存塊帘撰,而且,通過多次不同時間點的pmap -px輸出結(jié)果來看摧找,這種1MB大小的內(nèi)存塊還在不斷增長。到這里牢硅,聯(lián)想到上面的連續(xù)的64MB大小的內(nèi)存快,迅速找到了當時留的文檔鏈接
Linux glibc >= 2.10 (RHEL 6) malloc may show excessive virtual memory usage
這篇文章里明確提到:
These memory pools are called arenas and the implementation is in arena.c. The first important macro is HEAP_MAX_SIZE which is the maximum size of an arena and it is basically 1MB on 32-bit and 64MB on 64-bit:
HEAP_MAX_SIZE = (2 * DEFAULT_MMAP_THRESHOLD_MAX)
32-bit [DEFAULT_MMAP_THRESHOLD_MAX = (512 * 1024)] = 1,048,576 (1MB)
64-bit [DEFAULT_MMAP_THRESHOLD_MAX = (4 * 1024 * 1024 * sizeof(long))] = 67,108,864 (64MB)
32-bit應用程序Arena的大小最大為1MB减余,64-bit應用程序最大為64MB综苔,這次終于見識到了。
32-bit應用程序,sizeof(long) = 4 bit如筛,那么這個計算系數(shù)就是 2(sizeof(long) == 4 ? 2 : 8)
按照Arena數(shù)量最大值的計算公式:
**maximum number of arenas = NUMBER_OF_CPU_CORES * (sizeof(long) == 4 ? 2 : 8) **計算堡牡,當前系統(tǒng)80核CPU,那么理論上該Java虛擬機進程最大的Arena值就是 80 * 2 * 1(MB)= 160MB杨刨,但實際上晤柄,通過pmap觀察到這個進程這種1MB大小的匿名內(nèi)存塊都有700多MB,又看了下當前操作系統(tǒng)中g(shù)libc的版本是1.12妖胀,聯(lián)想到故障案例一中設(shè)置的MALLOC_ARENA_MAX=4在1.12版本都不生效的問題芥颈,遇到這種現(xiàn)象就不足為奇了。
目前做粤,RHEL 5.x浇借、6.x、7.3中使用的glibc版本都比較舊(都是2012年及之前的版本了怕品,7.3中使用的glibc版本是2.17妇垢,6.x中使用的glibc版本是2.12),可考慮在不是很重要的系統(tǒng)中保持glibc版本始終為最新肉康,然后再觀察Arena內(nèi)存的使用闯估。
解決辦法:
這次直接設(shè)置MALLOC_ARENA_MAX=1,只保留main arena吼和,禁用掉per thread arena內(nèi)存池涨薪,使其與RHEL 5.x版本保持一致,問題得以解決炫乓,設(shè)置完刚夺,Java虛擬機不再Crash,pmap監(jiān)控WebLogic/JVM進程使用的內(nèi)存增長明顯變少末捣、變緩侠姑。當然,設(shè)置完MALLOC_ARENA_MAX=1箩做,該WebLogic/JVM進程的Native Memory分配莽红、重用、回收等性能多多少少會受到一些影響邦邦,也可以使用Google的tcmalloc解決安吁。
總結(jié)
通過這兩個故障案例可以看出,從glibc 2.11(為應用系統(tǒng)在多核心CPU和多Sockets環(huán)境中高伸縮性提供了一個動態(tài)內(nèi)存分配的特性增強)版本開始引入了per thread arena內(nèi)存池燃辖,Native Heap區(qū)被打散為sub-pools 鬼店,這部分內(nèi)存池叫做Arena內(nèi)存池。也就是說黔龟,以前只有一個main arena薪韩,目前是一個main arena(還是位于Native Heap區(qū)) + 多個per thread arena,多個線程之間不再共用一個arena內(nèi)存區(qū)域了,保證每個線程都有一個堆观谦,這樣避免內(nèi)存分配時需要額外的鎖來降低性能。main arena主要通過brk/sbrk系統(tǒng)調(diào)用去管理捉偏,per thread arena主要通過mmap系統(tǒng)調(diào)用去分配和管理夭禽。
我們來看下線程申請per thread arena內(nèi)存池的流程:
Unlimited MALLOC_ARENAS_MAX
- Thread asks for an per thread arena
- Thread gets an per thread arena
- Thread fills arena, never frees memory
- Thread asks for an new per thread arena
- ............
- When no more per thread arena will be created, reused_arena function will be called to reuse arena already existed.
我們知道了main arena讹躯、per thread arena缠劝,那么一個Java虛擬機進程究竟能創(chuàng)建多少個arena惨恭、每個arena的大小又是多少那?這部分理論知識比較常見萝究,還不清楚的童鞋锉罐,我再啰嗦一下氓鄙,貼一遍:
一個32位的應用程序進程,最大可創(chuàng)建 2 * CPU總核數(shù)個arena內(nèi)存池(MALLOC_ARENA_MAX)升酣,每個arena內(nèi)存池大小為1MB
一個64位的應用程序進程噩茄,最大可創(chuàng)建 8 * CPU總核數(shù)個arena內(nèi)存池(MALLOC_ARENA_MAX),每個arena內(nèi)存池大小為64MB
理論歸理論绩聘,glibc 2.12版本(也就是RHEL 6.x中默認自帶的)在arena內(nèi)存分配和管理上,由于不少的Bug或目前我還沒完全弄明白的理論的存在机杜,實際上用pmap看到的1MB或64MB的anonymous memory(縮寫為anon)并不完全遵循MALLOC_ARENA_MAX個數(shù)設(shè)置椒拗。
除故障案例一中提到的幾處bug文章外获黔,還有兩個地方的文檔顯示,MALLOC_ARENA_MAX個數(shù)并不是按照設(shè)計那樣的工作堵未,多線程應用經(jīng)常遇到RSS渗蟹、VIRT內(nèi)存持續(xù)升高的情況耻陕,尤其是CPU核數(shù)多的系統(tǒng)環(huán)境诗宣。
glibc incorrectly allocated too much memory due to a race condition
within its own malloc routines. This could cause a multi-threaded
application to allocate more memory than was expected.
RHSA-2012:0058 - Security Advisory
文章地址:https://access.redhat.com/errata/RHSA-2012:0058
Linux check M_ARENA_TEST, and M_ARENA_MAX ?
文章地址:https://www.zhihu.com/question/64733296
如果不考慮內(nèi)存分配的性能召庞,遇到這樣的問題時,可使用export MALLOC_ARENA_MAX=1禁用per thread arena忘古,只用main arena诅诱,多個線程共用一個arena內(nèi)存池。如果考慮到性能干旁,可使用tcmalloc或jemalloc替代操作系統(tǒng)自帶的glibc管理內(nèi)存争群。
上面兩個故障案例都是Sun HotSpot JVM的大年,另外玉雾,IBM JDK和Oracle JRockit在RHEL 6.x操作系統(tǒng)環(huán)境運行時复旬,也會遇到Arena內(nèi)存使用上的問題赢底,詳見:
IBM JDK虛擬內(nèi)存使用量過高
Linux glibc >= 2.10 (RHEL 6) malloc may show excessive virtual memory usage(文章開頭部分)
Oracle JRockit虛擬機print_memusage輸出的other內(nèi)存使用過高
"Other" Allocation Reported By JRCMD print_memusage Is Too High And Causing An OutOfMemory Issue (Doc ID 2073773.1) (請在My Oracle Support站點搜索文章號)
轉(zhuǎn)型之路,《未來數(shù)據(jù)庫的發(fā)展方向與DBA轉(zhuǎn)型之路的解讀分析》系列文檔
mobike粹庞,摩拜物聯(lián)網(wǎng)架構(gòu)演進之路ppt返回搜狐庞溜,查看更多
責任編輯:
</article>
聲明:該文觀點僅代表作者本人,搜狐號系信息發(fā)布平臺又官,搜狐僅提供信息存儲空間服務六敬。
閱讀 ()
大家都在看
推薦閱讀