最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文帶你理解為什么Linux下多線程程序如此消耗虛擬內(nèi)存!(從這四點入手)

2022-05-18 20:00 作者:補給站Linux內(nèi)核  | 我要投稿

最近在進行服務(wù)器內(nèi)存優(yōu)化的時候,發(fā)現(xiàn)一個非常奇妙的問題,我們的認證服務(wù)器(AuthServer)負責跟第三方渠道SDK打交道,由于采用了curl阻塞的方式,所以這里開了128個線程,奇怪的是每次剛啟動的時候占用的虛擬內(nèi)存在2.3G,然后每次處理消息就增加64M,增加到4.4G就不再增加了,由于我們采用預(yù)分配的方式,在線程內(nèi)部根本沒有大塊分內(nèi)存,那么這些內(nèi)存到底是從哪來的呢?讓人百思不得其解。

探索

  • 一開始首先排除掉內(nèi)存泄露,不可能每次都泄露64M內(nèi)存這么巧合,為了證明我的觀點,首先,我使用了valgrind。

  • 然后啟動測試,跑至內(nèi)存不再增加,果然valgrind顯示沒有任何內(nèi)存泄露。反復試驗了很多次,結(jié)果都是這樣。

  • 在多次使用valgrind無果以后,我開始懷疑程序內(nèi)部是不是用到mmap之類的調(diào)用,于是使用strace對mmap,brk等系統(tǒng)函數(shù)的檢測:

其結(jié)果如下:

我檢查了一下trace文件也沒有發(fā)現(xiàn)大量內(nèi)存mmap動作,即便是brk動作引起的內(nèi)存增長也不大。于是感覺人生都沒有方向了,然后懷疑是不是文件緩存把虛擬內(nèi)存占掉了,注釋掉了代碼中所有讀寫日志的代碼,虛擬內(nèi)存依然增加,排除了這個可能。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。∏?00名進群領(lǐng)取,額外贈送一份價值699的內(nèi)核資料包(含視頻教程、電子書、實戰(zhàn)項目及代碼)? ? ?


靈光一現(xiàn)

  • 后來,我開始減少thread的數(shù)量開始測試,在測試的時候偶然發(fā)現(xiàn)一個很奇怪的現(xiàn)象。那就是如果進程創(chuàng)建了一個線程并且在該線程內(nèi)分配一個很小的內(nèi)存1k,整個進程虛擬內(nèi)存立馬增加64M,然后再分配,內(nèi)存就不增加了。測試代碼如下:

  • 其運行結(jié)果如下圖,剛開始時,進程占用虛擬內(nèi)存14M,輸入0,創(chuàng)建子線程,進程內(nèi)存達到23M,這增加的10M是線程堆棧的大小(查看和設(shè)置線程堆棧大小可用ulimit –s),第一次輸入1,程序分配1k內(nèi)存,整個進程增加64M虛擬內(nèi)存,之后再輸入2,3,各再次分配1k,內(nèi)存均不再變化。

  • 這個結(jié)果讓我欣喜若狂,由于以前學習過谷歌的Tcmalloc,其中每個線程都有自己的緩沖區(qū)來解決多線程內(nèi)存分配的競爭,估計新版的glibc同樣學習了這個技巧,于是查看pmap $(pidof main) 查看內(nèi)存情況,如下:

  • 請注意65404這一行,種種跡象表明,這個再加上它上面那一行(在這里是132)就是增加的那個64M)。后來增加thread的數(shù)量,就會有新增thread數(shù)量相應(yīng)的65404的內(nèi)存塊。

刨根問底

  • 經(jīng)過一番搜索和代碼查看。終于知道了原來是glibc的malloc在這里搗鬼。glibc 版本大于2.11的都會有這個問題:在redhat 的官方文檔上:

  • 總結(jié)一下,glibc為了分配內(nèi)存的性能的問題,使用了很多叫做arena的memory pool,缺省配置在64bit下面是每一個arena為64M,一個進程可以最多有 cores * 8個arena。假設(shè)你的機器是4核的,那么最多可以有4 * 8 = 32個arena,也就是使用32 * 64 = 2048M內(nèi)存。 當然你也可以通過設(shè)置環(huán)境變量來改變arena的數(shù)量.例如export MALLOC_ARENA_MAX=1

  • hadoop推薦把這個值設(shè)置為4。當然了,既然是多核的機器,而arena的引進是為了解決多線程內(nèi)存分配競爭的問題,那么設(shè)置為cpu核的數(shù)量估計也是一個不錯的選擇。設(shè)置這個值以后最好能對你的程序做一下壓力測試,用以看看改變arena的數(shù)量是否會對程序的性能有影響。

  • mallopt(M_ARENA_MAX, xxx)如果你打算在程序代碼中來設(shè)置這個東西,那么可以調(diào)用

  • mallopt(M_ARENA_MAX, xxx)來實現(xiàn),由于我們AuthServer采用了預(yù)分配的方式,在各個線程內(nèi)并沒有分配內(nèi)存,所以不需要這種優(yōu)化,在初始化的時候采用mallopt(M_ARENA_MAX, 1)將其關(guān)掉,設(shè)置為0,表示系統(tǒng)按CPU進行自動設(shè)置。

意外發(fā)現(xiàn)

  • 想到tcmalloc小對象才從線程自己的內(nèi)存池分配,大內(nèi)存仍然從中央分配區(qū)分配,不知道glibc是如何設(shè)計的,于是將上面程序中線程每次分配的內(nèi)存從1k調(diào)整為1M,果然不出所料,再分配完64M后,仍然每次都會增加1M,由此可見,新版 glibc完全借鑒了tcmalloc的思想。

  • 忙了幾天的問題終于解決了,心情大好,通過今天的問題讓我知道,作為一個服務(wù)器程序員,如果不懂編譯器和操作系統(tǒng)內(nèi)核,是完全不合格的,以后要加強這方面的學習。


一文帶你理解為什么Linux下多線程程序如此消耗虛擬內(nèi)存!(從這四點入手)的評論 (共 條)

分享到微博請遵守國家法律
宕昌县| 施甸县| 拉孜县| 永春县| 禹城市| 塘沽区| 咸阳市| 轮台县| 泽库县| 乌拉特后旗| 广东省| 定州市| 米易县| 松滋市| 北票市| 宁陕县| 元朗区| 绥滨县| 农安县| 昆山市| 喀喇沁旗| 佛坪县| 达尔| 上饶县| 镇坪县| 望城县| 长葛市| 焦作市| 田东县| 乐平市| 双江| 双牌县| 舟曲县| 社会| 汽车| 永济市| 阿瓦提县| 姚安县| 安康市| 邵阳市| 高邑县|