精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Spring Boot 引起的“堆外內存泄漏”排查及經驗總結

開發 后端
筆者在發表這篇文章時,發現Spring Boot的最新版本(2.0.5.RELEASE)已經做了修改,在ZipInflaterInputStream主動釋放了堆外內存不再依賴GC;所以Spring Boot升級到最新版本,這個問題也可以得到解決。

背景?

為了更好地實現對項目的管理,我們將組內一個項目遷移到MDP框架(基于Spring Boot),隨后我們就發現系統會頻繁報出Swap區域使用量過高的異常。筆者被叫去幫忙查看原因,發現配置了4G堆內內存,但是實際使用的物理內存竟然高達7G,確實不正常。JVM參數配置是“-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+AlwaysPreTouch -XX:ReservedCodeCacheSize=128m -XX:InitialCodeCacheSize=128m, -Xss512k -Xmx4g -Xms4g,-XX:+UseG1GC -XX:G1HeapRegionSize=4M”,實際使用的物理內存如下圖所示:

圖片

top命令顯示的內存情況

排查過程?

1. 使用Java層面的工具定位內存區域(堆內內存、Code區域或者使用unsafe.allocateMemory和DirectByteBuffer申請的堆外內存)

筆者在項目中添加??-XX:NativeMemoryTracking=detail??JVM參數重啟項目,使用命令??jcmd pid VM.native_memory detail??查看到的內存分布如下:

圖片

jcmd顯示的內存情況

發現命令顯示的committed的內存小于物理內存,因為jcmd命令顯示的內存包含堆內內存、Code區域、通過unsafe.allocateMemory和DirectByteBuffer申請的內存,但是不包含其他Native Code(C代碼)申請的堆外內存。所以猜測是使用Native Code申請內存所導致的問題。

為了防止誤判,筆者使用了pmap查看內存分布,發現大量的64M的地址;而這些地址空間不在jcmd命令所給出的地址空間里面,基本上就斷定就是這些64M的內存所導致。

圖片

pmap顯示的內存情況

2. 使用系統層面的工具定位堆外內存

因為筆者已經基本上確定是Native Code所引起,而Java層面的工具不便于排查此類問題,只能使用系統層面的工具去定位問題。

首先,使用了gperftools去定位問題

gperftools的使用方法可以參考gperftools:??https://github.com/gperftools/gperftools??,gperftools的監控如下:

圖片

gperftools監控

從上圖可以看出:使用malloc申請的的內存最高到3G之后就釋放了,之后始終維持在700M-800M。筆者第一反應是:難道Native Code中沒有使用malloc申請,直接使用mmap/brk申請的?(gperftools原理就使用動態鏈接的方式替換了操作系統默認的內存分配器(glibc)。)

然后,使用strace去追蹤系統調用

因為使用gperftools沒有追蹤到這些內存,于是直接使用命令“strace -f -e”brk,mmap,munmap” -p pid”追蹤向OS申請內存請求,但是并沒有發現有可疑內存申請。strace監控如下圖所示:

圖片

strace監控

接著,使用GDB去dump可疑內存

因為使用strace沒有追蹤到可疑內存申請;于是想著看看內存中的情況。就是直接使用命令??gdp -pid pid??進入GDB之后,然后使用命令??dump memory mem.bin startAddress endAddress??dump內存,其中startAddress和endAddress可以從/proc/pid/smaps中查找。然后使用??strings mem.bin??查看dump的內容,如下:

圖片

gperftools監控

從內容上來看,像是解壓后的JAR包信息。讀取JAR包信息應該是在項目啟動的時候,那么在項目啟動之后使用strace作用就不是很大了。所以應該在項目啟動的時候使用strace,而不是啟動完成之后。

再次,項目啟動時使用strace去追蹤系統調用

項目啟動使用strace追蹤系統調用,發現確實申請了很多64M的內存空間,截圖如下:

圖片

strace監控

使用該mmap申請的地址空間在pmap對應如下:

圖片

strace申請內容對應的pmap地址空間

最后,使用jstack去查看對應的線程

因為strace命令中已經顯示申請內存的線程ID。直接使用命令??jstack pid??去查看線程棧,找到對應的線程棧(注意10進制和16進制轉換)如下:

圖片

strace申請空間的線程棧

這里基本上就可以看出問題來了:MCC(美團統一配置中心)使用了Reflections進行掃包,底層使用了Spring Boot去加載JAR。因為解壓JAR使用Inflater類,需要用到堆外內存,然后使用Btrace去追蹤這個類,棧如下:

圖片

btrace追蹤棧

然后查看使用MCC的地方,發現沒有配置掃包路徑,默認是掃描所有的包。于是修改代碼,配置掃包路徑,發布上線后內存問題解決。

3. 為什么堆外內存沒有釋放掉呢?

雖然問題已經解決了,但是有幾個疑問:

  • 為什么使用舊的框架沒有問題?
  • 為什么堆外內存沒有釋放?
  • 為什么內存大小都是64M,JAR大小不可能這么大,而且都是一樣大?
  • 為什么gperftools最終顯示使用的的內存大小是700M左右,解壓包真的沒有使用malloc申請內存嗎?

帶著疑問,筆者直接看了一下Spring Boot Loader:??https://github.com/spring-projects/spring-boot/tree/master/spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader??那一塊的源碼。發現Spring Boot對Java JDK的InflaterInputStream進行了包裝并且使用了Inflater,而Inflater本身用于解壓JAR包的需要用到堆外內存。而包裝之后的類ZipInflaterInputStream沒有釋放Inflater持有的堆外內存。于是筆者以為找到了原因,立馬向Spring Boot社區反饋了這個bug:??https://github.com/spring-projects/spring-boot/issues/13935??。但是反饋之后,筆者就發現Inflater這個對象本身實現了finalize方法,在這個方法中有調用釋放堆外內存的邏輯。也就是說Spring Boot依賴于GC釋放堆外內存。

筆者使用jmap查看堆內對象時,發現已經基本上沒有Inflater這個對象了。于是就懷疑GC的時候,沒有調用finalize。帶著這樣的懷疑,筆者把Inflater進行包裝在Spring Boot Loader里面替換成自己包裝的Inflater,在finalize進行打點監控,結果finalize方法確實被調用了。于是筆者又去看了Inflater對應的C代碼,發現初始化的使用了malloc申請內存,end的時候也調用了free去釋放內存。

此刻,筆者只能懷疑free的時候沒有真正釋放內存,便把Spring Boot包裝的InflaterInputStream替換成Java JDK自帶的,發現替換之后,內存問題也得以解決了。

這時,再返過來看gperftools的內存分布情況,發現使用Spring Boot時,內存使用一直在增加,突然某個點內存使用下降了好多(使用量直接由3G降為700M左右)。這個點應該就是GC引起的,內存應該釋放了,但是在操作系統層面并沒有看到內存變化,那是不是沒有釋放到操作系統,被內存分配器持有了呢?

繼續探究,發現系統默認的內存分配器(glibc 2.12版本)和使用gperftools內存地址分布差別很明顯,2.5G地址使用smaps發現它是屬于Native Stack。內存地址分布如下:

圖片

gperftools顯示的內存地址分布

到此,基本上可以確定是內存分配器在搗鬼;搜索了一下glibc 64M,發現glibc從2.11開始對每個線程引入內存池(64位機器大小就是64M內存),原文如下:

圖片

glib內存池說明

按照文中所說去修改MALLOC_ARENA_MAX環境變量,發現沒什么效果。查看tcmalloc(gperftools使用的內存分配器)也使用了內存池方式。

為了驗證是內存池搞的鬼,筆者就簡單寫個不帶內存池的內存分配器。使用命令??gcc zjbmalloc.c -fPIC -shared -o zjbmalloc.so??生成動態庫,然后使用??export LD_PRELOAD=zjbmalloc.so??替換掉glibc的內存分配器。其中代碼Demo如下:

#include<sys/mman.h>
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
//作者使用的64位機器,sizeof(size_t)也就是sizeof(long)
void* malloc ( size_t size )
{
long* ptr = mmap( 0, size + sizeof(long), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0 );
if (ptr == MAP_FAILED) {
return NULL;
}
*ptr = size; // First 8 bytes contain length.
return (void*)(&ptr[1]); // Memory that is after length variable
}

void *calloc(size_t n, size_t size) {
void* ptr = malloc(n * size);
if (ptr == NULL) {
return NULL;
}
memset(ptr, 0, n * size);
return ptr;
}
void *realloc(void *ptr, size_t size)
{
if (size == 0) {
free(ptr);
return NULL;
}
if (ptr == NULL) {
return malloc(size);
}
long *plen = (long*)ptr;
plen--; // Reach top of memory
long len = *plen;
if (size <= len) {
return ptr;
}
void* rptr = malloc(size);
if (rptr == NULL) {
free(ptr);
return NULL;
}
rptr = memcpy(rptr, ptr, len);
free(ptr);
return rptr;
}

void free (void* ptr )
{
if (ptr == NULL) {
return;
}
long *plen = (long*)ptr;
plen--; // Reach top of memory
long len = *plen; // Read length
munmap((void*)plen, len + sizeof(long));
}

通過在自定義分配器當中埋點可以發現其實程序啟動之后應用實際申請的堆外內存始終在700M-800M之間,gperftools監控顯示內存使用量也是在700M-800M左右。但是從操作系統角度來看進程占用的內存差別很大(這里只是監控堆外內存)。

筆者做了一下測試,使用不同分配器進行不同程度的掃包,占用的內存如下:

圖片

內存測試對比

為什么自定義的malloc申請800M,最終占用的物理內存在1.7G呢?

因為自定義內存分配器采用的是mmap分配內存,mmap分配內存按需向上取整到整數個頁,所以存在著巨大的空間浪費。通過監控發現最終申請的頁面數目在536k個左右,那實際上向系統申請的內存等于512k * 4k(pagesize) = 2G。為什么這個數據大于1.7G呢?

因為操作系統采取的是延遲分配的方式,通過mmap向系統申請內存的時候,系統僅僅返回內存地址并沒有分配真實的物理內存。只有在真正使用的時候,系統產生一個缺頁中斷,然后再分配實際的物理Page。

總結?

圖片

流程圖

整個內存分配的流程如上圖所示。MCC掃包的默認配置是掃描所有的JAR包。在掃描包的時候,Spring Boot不會主動去釋放堆外內存,導致在掃描階段,堆外內存占用量一直持續飆升。當發生GC的時候,Spring Boot依賴于finalize機制去釋放了堆外內存;但是glibc為了性能考慮,并沒有真正把內存歸返到操作系統,而是留下來放入內存池了,導致應用層以為發生了“內存泄漏”。所以修改MCC的配置路徑為特定的JAR包,問題解決。筆者在發表這篇文章時,發現Spring Boot的最新版本(2.0.5.RELEASE)已經做了修改,在ZipInflaterInputStream主動釋放了堆外內存不再依賴GC;所以Spring Boot升級到最新版本,這個問題也可以得到解決。

責任編輯:龐桂玉 來源: Hollis
相關推薦

2020-08-27 21:36:50

JVM內存泄漏

2022-07-03 20:31:59

JVMJava虛擬機

2018-12-04 09:07:36

運維問題排查

2009-06-10 16:48:54

NetBeans SV攻略

2009-10-15 09:27:00

2013-01-18 10:10:30

項目項目經理

2017-02-17 11:19:00

Android內存泄露分析總結

2011-07-21 13:40:17

java

2010-09-13 10:52:37

CSS定位

2009-09-16 17:13:54

學習Linq

2009-09-29 16:32:11

OJB Hiberna

2009-08-19 09:24:43

AJAX引擎經驗總結

2010-03-23 11:39:49

云計算

2010-03-25 13:42:14

云計算

2010-04-21 14:53:46

Oracle游標

2010-05-19 17:24:55

MySQL編碼

2011-07-08 13:15:52

JSP

2009-08-20 17:35:47

Servlet和JSP

2009-10-22 15:07:12

綜合布線工程

2009-09-08 10:57:55

LINQ查詢操作
點贊
收藏

51CTO技術棧公眾號

国产免费色视频| 欧美高跟鞋交xxxxxhd| 天天操天天爱天天爽| 黄色av电影在线观看| 成人18视频在线播放| 国产成人亚洲综合| 青青草手机视频在线观看| 亚洲婷婷影院| 欧美一区二区三区男人的天堂| av动漫在线看| 中文字幕在线观看网站| 久久久久久久av麻豆果冻| 51蜜桃传媒精品一区二区| 中文字幕亚洲精品一区| 亚洲成人精选| 亚洲一级黄色av| 喷水视频在线观看| 亚洲人成777| 色噜噜狠狠色综合中国| 日本天堂免费a| 成年人免费在线视频| 成人黄色大片在线观看| 国产综合久久久久| 中文字幕亚洲乱码熟女1区2区| 自拍视频亚洲| 综合网中文字幕| 女同毛片一区二区三区| 亚洲一区二区三区中文字幕在线观看| 欧美色倩网站大全免费| 又粗又黑又大的吊av| 91网址在线观看| 国产精品久久久久毛片软件| 久久久综合亚洲91久久98| 午夜精品小视频| 美女尤物国产一区| 国产成人精品视| 黄色在线免费观看| 一区二区三区国产盗摄| 欧美国产第二页| 亚洲国产美女视频| 天天综合国产| 日韩网站在线观看| 国产三级在线观看完整版| 亚洲免费成人av在线| 亚洲精品suv精品一区二区| 原创真实夫妻啪啪av| 色999韩欧美国产综合俺来也| 日本大香伊一区二区三区| 9久久9毛片又大又硬又粗| 91超碰在线免费| 亚洲成人久久影院| 131美女爱做视频| 51精品在线| 亚洲va中文字幕| 美女日批免费视频| 538在线观看| 精品日韩中文字幕| 欧美s码亚洲码精品m码| 黄频免费在线观看| 色综合久久九月婷婷色综合| 亚洲性生活网站| 国产精品亲子伦av一区二区三区| 欧美三电影在线| 日本中文字幕观看| 高清不卡一区| 精品国产麻豆免费人成网站| 大尺度在线观看| 亚洲精品推荐| 亚洲丝袜一区在线| 日本精品在线免费观看| 欧美日韩精品| 欧美亚洲激情视频| 中文字幕 亚洲视频| 激情深爱一区二区| 97超级碰碰| 先锋av资源站| 国产精品天干天干在线综合| 久久久成人精品一区二区三区| 人妖欧美1区| 欧美日韩午夜视频在线观看| 九色porny91| 国产精品白丝久久av网站| 精品不卡在线视频| 波多野结衣av在线观看| 99久久婷婷| 久久久爽爽爽美女图片| 免费无码国产精品| 国产成人精品影视| 青青草原成人| 四虎亚洲精品| 91成人国产精品| 日本高清免费观看| 女人av一区| 北条麻妃一区二区三区中文字幕| 黄色小视频在线免费看| 日韩不卡一区二区三区| 成人综合色站| www亚洲人| 午夜电影网一区| 亚洲最大成人在线观看| 国产精品调教| 久久精品久久精品亚洲人| 日韩特级黄色片| 国产精品一区二区视频| 日本一区二区不卡高清更新| 五月花成人网| 欧美日韩一级二级| 精品无码国产一区二区三区51安| 国产精品久久久久久| 热久久美女精品天天吊色| www.成人精品| 中文字幕在线一区| 男人插女人下面免费视频| 久久精品色综合| 欧美大片免费观看| 国产乱码精品一区二区| 久久久91精品国产一区二区精品 | 九一成人免费视频| 久久99热这里只有精品国产| 亚洲视频一区二区三区四区| 久久综合成人精品亚洲另类欧美| 国内自拍中文字幕| 伊人久久大香伊蕉在人线观看热v| 日韩精品亚洲精品| 日本熟妇乱子伦xxxx| 国产一区二区三区四区五区入口 | 免费黄色在线视频| 黄色工厂这里只有精品| 亚洲自拍av在线| 毛片av在线| 欧美性猛交一区二区三区精品| 日本丰满少妇裸体自慰| 99精品国产福利在线观看免费 | 欧洲专线二区三区| 68精品久久久久久欧美| 免费看av毛片| 亚洲图片欧美色图| 精品人妻在线视频| 欧美日韩国产综合网| 亚洲综合大片69999| 成人在线免费看黄| 欧美一区二区三区不卡| 国产福利视频网站| 国产精品一区二区在线看| 久久99国产精品一区| 欧美国产亚洲精品| 九九热这里只有精品免费看| www.黄色一片| 亚洲国产精品一区二区久久恐怖片 | www.av免费| 国产精品综合一区二区三区| 奇米777四色影视在线看| 亚洲一区 二区| 97香蕉超级碰碰久久免费的优势| 天天舔天天干天天操| 五月天中文字幕一区二区| 香港三级日本三级| 久久一区视频| 亚洲国产一区二区精品视频 | 国产一区在线观看免费| 国产一区二三区| 日韩久久久久久久久久久久| 女同另类激情重口| 日本精品久久久久久久| av影片免费在线观看| 欧美美女直播网站| 国产大片中文字幕| 337p粉嫩大胆色噜噜噜噜亚洲| aaa毛片在线观看| 91亚洲国产高清| 国产福利久久精品| 高清不卡av| 久久精品国产91精品亚洲| 午夜精品小视频| 欧美性xxxxxxx| 最新av电影网站| 成人av电影在线网| 91国产精品视频在线观看| 欧美va亚洲va日韩∨a综合色| 成人观看高清在线观看免费| 欧美xxxx做受欧美88bbw| 亚洲精品一区久久久久久| 日韩三级成人| 色综合久久88| 欧美日韩在线中文字幕| 欧美日韩卡一卡二| 伊人365影院| 国产视频一区二区在线观看| 性久久久久久久久久久久久久| 亚洲精品乱码| 夜夜春亚洲嫩草影视日日摸夜夜添夜| 亚洲精品一区国产| 国产999精品久久久| 91香蕉在线观看| 亚洲色图13p| 亚洲va欧美va| 欧美日韩精品电影| 午夜婷婷在线观看| 亚洲精品五月天| 日本欧美一区二区三区不卡视频| 国产成人精品免费看| 久久久久久久久久久久91| 红桃视频国产精品| 色香蕉在线观看| 久操精品在线| 国产精品久久久久久免费观看 | 福利视频第一区| 国产精品白丝喷水在线观看| 国产亚洲欧美激情| 中文在线观看免费视频| 国产在线视频精品一区| 虎白女粉嫩尤物福利视频| 亚洲高清在线| av动漫在线免费观看| 日本不卡高清| 欧美日韩国产精品一卡| 久久porn| 国产一区二区在线网站| 欧美经典影片视频网站| 国产伦精品一区二区三区精品视频| 在线男人天堂| 97视频免费看| 丰满大乳少妇在线观看网站| 久热99视频在线观看| 日本成人在线播放| 尤物九九久久国产精品的特点| 日本一区二区三区在线观看视频| 亚洲第一精品电影| 亚洲毛片欧洲毛片国产一品色| 欧美片网站yy| 中文字幕视频免费观看| 欧洲视频一区二区| 亚洲中文字幕无码爆乳av| 欧美性xxxx18| 波多野结衣啪啪| 色哟哟国产精品免费观看| 天天综合网入口| 亚洲va欧美va天堂v国产综合| 国产一级视频在线| 亚洲国产日韩a在线播放性色| 毛片a片免费观看| 亚洲综合丝袜美腿| 久久精品免费av| 午夜天堂影视香蕉久久| 你懂的国产视频| 欧美日韩国产专区| 亚洲免费激情视频| 欧美性猛交xxxx免费看久久久| 中文字幕视频网| 日本丰满少妇一区二区三区| 国产美女www| 欧美日韩和欧美的一区二区| 国产剧情久久久| 日韩精品专区在线影院重磅| 免费观看成年人视频| 精品呦交小u女在线| 国产高清自拍视频在线观看| 中文字幕精品一区久久久久| 国产黄色在线观看| 久久久久久久久国产| 在线观看特色大片免费视频| 国产成人精品久久| 日韩一级特黄| 国产成人免费观看| 免费看日本一区二区| 亚洲蜜桃在线| 黄色成人在线网站| 成人免费xxxxx在线视频| 精品亚洲国内自在自线福利| 无码国产精品一区二区高潮| 99久久久久久99| 亚洲国产天堂av| 亚洲欧洲综合另类在线| 一区视频免费观看| 色综合天天综合色综合av| 夜夜躁很很躁日日躁麻豆| 亚洲精品一区在线观看| 国产一二三在线观看| 久久亚洲春色中文字幕| 欧美aaaaa性bbbbb小妇| 国产欧美精品久久久| 精品国产导航| 亚洲欧洲中文| 亚洲精品123区| 777一区二区| 99麻豆久久久国产精品免费优播| 在线看片中文字幕| 亚洲国产精品久久不卡毛片| 中文字幕+乱码+中文乱码www| 日韩一级欧美一级| 大乳在线免费观看| 欧美精品videossex性护士| www.26天天久久天堂| 成人黄视频免费| 日韩在线观看一区 | 国产精品自拍网站| 伊人网伊人影院| 亚洲一级二级三级| 亚洲综合视频在线播放| 日韩精品小视频| 久久不射影院| 亚洲a中文字幕| 国产一区三区在线播放| 日本中文字幕在线视频观看| 蜜臂av日日欢夜夜爽一区| 日韩av手机在线播放| 亚洲欧美国产毛片在线| 香蕉污视频在线观看| 亚洲国产日韩一区| 亚洲区欧洲区| 国产自摸综合网| 欧美日韩一区二区三区视频播放| 国产精品久久中文字幕| 国产成人鲁色资源国产91色综| 91无套直看片红桃在线观看| 日韩欧美中文第一页| 国产免费久久久| 日韩中文字幕网站| 主播大秀视频在线观看一区二区| 久久精品二区| 精品电影一区| 欧美一区二区三区影院| 综合色中文字幕| 亚洲一区二区天堂| 中文字幕精品在线| 久久日本片精品aaaaa国产| 欧美激情一区二区三区在线视频 | 国产精品高潮呻吟久久av无限| 加勒比视频一区| 国产玉足脚交久久欧美| 国产白丝精品91爽爽久久| 国产日韩欧美在线观看视频| 欧美丰满少妇xxxbbb| 色三级在线观看| 国产一区视频在线| 婷婷亚洲五月| 国产三级精品三级在线| 国产精品久久久久一区二区三区 | 日本少妇做爰全过程毛片| 精品久久国产老人久久综合| 欧美精品videosex| 岛国视频一区| 国产人成精品一区二区三| 日韩精品人妻中文字幕有码| 图片区日韩欧美亚洲| 视频国产一区二区三区| 欧洲精品久久久| 禁果av一区二区三区| 色悠悠久久综合网| 国产精品传媒视频| 99在线小视频| 久久久久国产精品www| 欧美大片网址| 黄色高清无遮挡| 国产精品免费久久久久| 国产一区二区视频免费观看| 欧美成人免费全部| 草草视频在线一区二区| 99热在线这里只有精品| 国产日韩一级二级三级| 亚洲一区二区影视| 色综合久久久888| 天堂综合网久久| 色乱码一区二区三区在线| 亚洲女同ⅹxx女同tv| 黄片毛片在线看| 热久久99这里有精品| 国产精品97| 国产chinese中国hdxxxx| 91福利在线导航| 91在线中文| 欧美深深色噜噜狠狠yyy| 毛片一区二区三区| 久久久久亚洲AV| 亚洲视屏在线播放| 天堂精品久久久久| 欧美精品第三页| 亚洲少妇中出一区| 神马精品久久| 91免费视频国产| 国产亚洲在线观看| 日本美女黄色一级片| 亚洲激情视频网| 日韩第二十一页| 又粗又黑又大的吊av| 国产精品丝袜黑色高跟| 日本黄视频在线观看| 成人a免费视频| 国产精品久久久久久久久久妞妞 | 亚洲电影在线播放| h网站在线免费观看| 国产日韩欧美一区二区| 男人的天堂亚洲一区| 国产无码精品在线播放| 色偷偷综合社区| 日韩欧美在线精品| 四虎1515hh.com| 91福利在线观看| 蜜桃麻豆影像在线观看| 男女爱爱视频网站|