欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

jvm堆外內(nèi)存排查圖文舉例詳解

 更新時間:2023年12月15日 09:27:02   作者:Xd聊架構(gòu)  
Java應(yīng)用程序通過直接方式從操作系統(tǒng)中申請的內(nèi)存,叫堆外內(nèi)存,這篇文章主要給大家介紹了關(guān)于jvm堆外內(nèi)存排查的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

內(nèi)存泄漏想必大家并不陌生,對于jvm的內(nèi)存泄漏,有很多排查手段和方便的排查工具,例如MAL,但是對于非jvm的內(nèi)存,如直接內(nèi)存的使用,排查起來較為麻煩,下面介紹一下相關(guān)的排查手段

一、堆外內(nèi)存排查

1.背景

在一次內(nèi)存檢查的過程中,意外發(fā)現(xiàn)在linux的java進程內(nèi)存占用,遠高于jvm的內(nèi)存設(shè)定最大值(堆+非堆),第一時間是考慮java可以采用直接內(nèi)存,如mmap對內(nèi)存進行使用,但經(jīng)過排查,發(fā)現(xiàn)并非如此,下面看一下排查過程

2.內(nèi)存對比

首先通過top,可以看到j(luò)ava進行使用了4.2g的內(nèi)存,且pid為2730

ps -ef|grep java
top -pid 2730

因為我知道我的jvm最大內(nèi)存設(shè)置為3G左右,所以第一時間就沒有去看JVM的最大值,如果不確定,優(yōu)先查看JVM的堆、非堆的內(nèi)存分配情況,本次忽略,直接查看NMT。

為了觀察java進程堆外內(nèi)存的占用,JVM啟動參數(shù)中添加參數(shù):-XX:NativeMemoryTracking=summary,這個參數(shù)對jvm可能會有5%左右的性能損耗,所以生產(chǎn)環(huán)境不推薦開啟。

同時,-XX:+DisableExplicitGC:禁止顯示GC,即代碼中聲明的 System.gc();//建議jvm進行g(shù)c 不再生效。在jdk源碼中使用nio申請堆外內(nèi)存時,堆外內(nèi)存不足時會執(zhí)行 System.gc() 進行堆外內(nèi)存的回收,所以,堆外內(nèi)存使用較多時不推薦配置 -XX:+DisableExplicitGC。

最后,為了防止堆外內(nèi)存的溢出,jvm啟動參數(shù)可以換添加:-XX:MaxDirectMemorySize=1024M

開啟NMT后,通過jcmd命令查看內(nèi)存情況

jcmd 2730 VM.native_memory scale=MB

Heap(堆)、Class(元空間)、Thread(java線程棧,含GC本地線程)、Code(本地字節(jié)碼,即JIT存儲熱點代碼地方)、GC(JVM GC額外占用的,例如G1中的Remembered Set等數(shù)據(jù)結(jié)構(gòu))、Internal(Direct Buffer直接內(nèi)存,例如nio)等占用。Native Memory Tracking表示該功能自身占用的部分。

JVM 的內(nèi)存大致分為下面這幾個部分:

  • 堆(Heap):young、old 區(qū)域等
  • 線程棧(Thread Stack):每個線程棧預(yù)留 1M 的線程棧大小
  • 非堆(Non-heap):包括 code_cache、metaspace 等
  • 堆外內(nèi)存:unsafe.allocateMemory 和 DirectByteBuffer 申請的堆外內(nèi)存
  • native (C/C++ 代碼)申請的內(nèi)存
  • 還有 JVM 運行本身需要的內(nèi)存,比如 GC 等

可以看到JVM只使用了3G左右,其中Internal的39M為直接內(nèi)存的使用,那么剩余的1.2G非JVM的使用。因為jcmd命令顯示的內(nèi)存包含堆內(nèi)內(nèi)存、Code區(qū)域、通過unsafe.allocateMemory和DirectByteBuffer申請的內(nèi)存,但是不包含其他Native Code(C代碼)申請的堆外內(nèi)存。所以猜測是使用Native Code申請內(nèi)存所導(dǎo)致的問題。

其他jcmd可用命令:

查看java進程內(nèi)存占用詳細情況(-XX:NativeMemoryTracking=summary,關(guān)閉NMT命令:jcmd pid VM.native_memory shutdown):
jcmd pid VM.native_memory scale=MB
 
保存java進程內(nèi)存占用情況的基準版本:
jcmd pid VM.native_memory scale=MB baseline
 
與基準版本進行比較(若懷疑存在內(nèi)存泄漏,可過段時間再執(zhí)行觀察):
jcmd pid VM.native_memory scale=MB summary.diff

3.堆外內(nèi)存檢查

通過pmap打印內(nèi)存的分布情況,并從打到小排序

pmap 2730 -x | sort -k 3 -n -r > /tmp/pmap20230131

打印jcmd內(nèi)存使用明細

jcmd 2730 VM.native_memory detail scale=MB > /tmp/jcmd20230131.txt

在pmap文件中,發(fā)現(xiàn)大量的64M的地址;而這些地址空間不在jcmd命令所給出的地址空間里面(例如通過pmap其中一個內(nèi)存地址7f6f90000000,去jcmd明細中搜索,無法搜到即為沒有在jvm中有引用),基本上就斷定就是這些64M的內(nèi)存所導(dǎo)致。

4.排查堆外內(nèi)存

因猜測是Native Code所引起,Java層面的工具不便于排查此類問題,只能使用系統(tǒng)層面的工具去定位問題。

1.使用smaps查看內(nèi)存的起始地址

cat /proc/2730/smaps > /tmp/smaps20230131.txt

以上述7f6f90000000地址為例,因在jcmd中無法找到7f6f90000000地址的內(nèi)容,說明非jvm內(nèi)存,在smaps文件中搜索7f6f90000000的起始地址。

2.使用gdb調(diào)試工具打印上述懷疑的內(nèi)存地址里面存儲的內(nèi)容(注:gdb從進入到退出的中間時刻,會使java進程無法訪問,處于掛起狀態(tài),生產(chǎn)環(huán)境小心使用)。

#進入gdb
gdb -pid 2730
#打印內(nèi)存地址地址內(nèi)容(0x00007f6f90000000 0x00007f6f93fff000)為開始地址和結(jié)束地址
dump memory mem.bin 0x00007f6f90000000 0x00007f6f93fff000
#退出
quit
#將文本以字符串輸出
strings mem.bin > /tmp/mem20230131.txt

因進入gdb會導(dǎo)致進程無法訪問,建議使用下面的方式執(zhí)行命令

#0x00007f6f90000000 可以寫成0x7f6f90000000 
gdb --batch --pid 2730-ex "dump memory /tmp/ipo02061143.bin 0x7f6f90000000 0x7f6f93fff000"

可以看看里面有一些報錯和具體的調(diào)用方法等,根據(jù)內(nèi)存里面的內(nèi)容進行逐一檢查即可

5.glibc內(nèi)存泄露

像上述的問題,內(nèi)存內(nèi)容里面沒有可疑點,并且pmap打印的內(nèi)容中有大量的64M內(nèi)存區(qū)域,由此可發(fā)現(xiàn),這是linux經(jīng)典的glibc內(nèi)存泄露問題,后續(xù)會專門寫一篇文章介紹linux內(nèi)存管理以及glibc相關(guān)的原理,這里先直接說明結(jié)論。

原因:

glibc 的內(nèi)存分配策略導(dǎo)致的碎片化內(nèi)存回收問題,導(dǎo)致看起來像是內(nèi)存泄露,那有沒有更好一點的對碎片化內(nèi)存的 malloc 庫呢?業(yè)界常見的有 google 家的 tcmalloc 和 facebook 家的 jemalloc。

tcmalloc

#安裝
yum install gperftools-libs.x86_64 
#使用 LD_PRELOAD 掛載
export LD_PRELOAD="/usr/lib64/libtcmalloc.so.4.4.5"

注意 java 應(yīng)用要重啟

jemalloc

#安裝
yum install epel-release  -y
yum install jemalloc -y
#使用 LD_PRELOAD 掛載
export LD_PRELOAD="/usr/lib64/libjemalloc.so.1"

使用 jemalloc 后,RSS 內(nèi)存呈周期性波動,波動范圍約 2 個百分點以內(nèi),基本控制住了

總結(jié)

到此這篇關(guān)于jvm堆外內(nèi)存排查的文章就介紹到這了,更多相關(guān)jvm堆外內(nèi)存排查內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論