chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

glibc內(nèi)存管理存在的共性問(wèn)題及解決方法

Linux閱碼場(chǎng) ? 來(lái)源:Linux閱碼場(chǎng) ? 作者:劉冬云 ? 2021-06-18 14:50 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

引言

對(duì)于嵌入式設(shè)備來(lái)說(shuō),用戶態(tài)內(nèi)存管理是一項(xiàng)基礎(chǔ)功能,目前主流的用戶態(tài)內(nèi)存管理庫(kù)有g(shù)libc、uclibc、tcmalloc、jemalloc等。

本文基于glibc2.17版本進(jìn)行分析,圍繞glibc內(nèi)存分配原理、內(nèi)存站崗問(wèn)題形成原因展開討論,并對(duì)glibc緩存大量?jī)?nèi)存(高達(dá)幾十個(gè) G甚至上百 G)且不釋放的問(wèn)題給出一種解決方案。

筆者遇到的問(wèn)題是基于glibc進(jìn)行內(nèi)存管理的64 位Linux系統(tǒng)。具體現(xiàn)象如下:設(shè)備32G物理內(nèi)存,在大規(guī)格打流情況下,某用戶進(jìn)程占用的物理內(nèi)存暴漲至20G左右。

在停止打流后,觀察到業(yè)務(wù)模塊已經(jīng)釋放了絕大部分內(nèi)存,但是進(jìn)程占用的物理內(nèi)存依然達(dá)到16G左右,此后內(nèi)存狀況一直維持該狀態(tài),導(dǎo)致系統(tǒng)內(nèi)存緊張,若疊加上其他業(yè)務(wù)則出現(xiàn)了OOM的現(xiàn)象,已排除該進(jìn)程內(nèi)存泄露的可能性。

1

Glibc內(nèi)存分配基本原理

Glibc使用了ptmalloc的內(nèi)存管理方式,本文在描述時(shí)均使用glibc來(lái)稱呼。Glibc申請(qǐng)內(nèi)存時(shí)是從分配區(qū)申請(qǐng)的,分為主分配區(qū)和非主分配區(qū),分配區(qū)都有鎖,在分配內(nèi)存前需要先獲取鎖,然后再去申請(qǐng)內(nèi)存。

一般進(jìn)程都是多線程的,當(dāng)多個(gè)線程同時(shí)需要申請(qǐng)內(nèi)存時(shí),如果只有一個(gè)分配區(qū),那么效率太低。

glibc為了支持多線程的內(nèi)存申請(qǐng)釋放,會(huì)在多個(gè)線程同時(shí)需要申請(qǐng)內(nèi)存時(shí)根據(jù)cpu核數(shù)分配一定數(shù)量的分配區(qū),將分配區(qū)分配給線程。如果線程數(shù)量較多,則會(huì)出現(xiàn)多個(gè)線程爭(zhēng)用一個(gè)分配區(qū)的的情況,這里不展開。

內(nèi)存申請(qǐng)基本原理:當(dāng)用戶調(diào)用malloc申請(qǐng)內(nèi)存時(shí),glibc會(huì)查看是否已經(jīng)緩存了內(nèi)存,如果有緩存則會(huì)優(yōu)先使用緩存內(nèi)存,返回一塊符合用戶請(qǐng)求大小的內(nèi)存塊。

如果沒(méi)有緩存或者緩存不足則會(huì)去向操作系統(tǒng)申請(qǐng)內(nèi)存(可通過(guò)brk、mmap申請(qǐng)內(nèi)存),然后切一塊內(nèi)存給用戶。

內(nèi)存釋放基本原理:當(dāng)業(yè)務(wù)模塊使用完畢后調(diào)用free釋放內(nèi)存時(shí),glibc會(huì)檢查該內(nèi)存塊虛擬地址上下內(nèi)存塊的使用狀態(tài)(fast bin除外)。若其上一塊內(nèi)存空閑,則與上一塊內(nèi)存進(jìn)行合并。若下一塊內(nèi)存空閑,則與下一塊內(nèi)存進(jìn)行合并。如圖2所示。

若下一塊內(nèi)存時(shí)top chunk(top chunk一直是空閑的),則看top chunk的大小是否超過(guò)一個(gè)閾值,如果超過(guò)一個(gè)閾值則將其釋放給OS。

2

Glibc內(nèi)存站崗及其原因

內(nèi)存站崗概念:

內(nèi)存站崗指的是glibc從OS申請(qǐng)到內(nèi)存后分配給業(yè)務(wù)模塊,業(yè)務(wù)模塊使用完畢后釋放了內(nèi)存,但是glibc沒(méi)有將這些空閑內(nèi)存釋放給OS,也就是緩存了很多空閑內(nèi)存無(wú)法歸還給系統(tǒng)的現(xiàn)象。

內(nèi)存站崗原因:

glibc設(shè)計(jì)時(shí)就確定其內(nèi)存是用于短生命周期的,因此在設(shè)計(jì)上內(nèi)存釋放給OS的時(shí)機(jī)是當(dāng)top chunk的大小超過(guò)一個(gè)閾值時(shí)會(huì)釋放top chunk的一部分內(nèi)存給OS。當(dāng)top chunk不超過(guò)閾值就不會(huì)釋放內(nèi)存給OS。

那么問(wèn)題來(lái)了,若與top chunk相鄰的內(nèi)存塊一直在使用中,那么top chunk就永遠(yuǎn)也不會(huì)超過(guò)閾值,即便業(yè)務(wù)模塊釋放了大量?jī)?nèi)存,達(dá)到幾十個(gè)G 或者上百個(gè)G,glibc也是無(wú)法將內(nèi)存還給OS的。

對(duì)于glibc來(lái)說(shuō),其有主分配和非主分配區(qū)的概念。主分配通過(guò)sbrk來(lái)增加分配區(qū)的內(nèi)存大小,而非主分配區(qū)則是通過(guò)一個(gè)或多個(gè)mmap出來(lái)的內(nèi)存塊用鏈表鏈接起來(lái)模擬主分配區(qū)的。為了更清晰的解釋內(nèi)存站崗,下面舉個(gè)例子來(lái)說(shuō)明主分配區(qū)的內(nèi)存站崗。

如上有(a) (c) (e) (g)內(nèi)存塊正在使用,故而導(dǎo)致了空閑內(nèi)存(b) (d) (f)無(wú)法和top chunk連成一塊更大的空閑內(nèi)存塊,glibc的閾值(64位系統(tǒng)默認(rèn)是128K),盡管目前空閑內(nèi)存有將近130M,也無(wú)法還給OS。

接下來(lái)看非主分配區(qū)的內(nèi)存站崗,實(shí)際的非主分配區(qū)可能有很多個(gè)heap,這里假設(shè)只有4個(gè)heap。

在定位過(guò)程中,筆者與同事討論過(guò)多次如何解決站崗。在一次討論過(guò)程中由鄧竑杰提出降低heap的size(類似于tcmalloc的做法),雖然實(shí)測(cè)后發(fā)現(xiàn)完全沒(méi)有效果,但是為后續(xù)解決問(wèn)題起到了啟示作用。

后面筆者在走讀代碼時(shí)發(fā)現(xiàn)這是glibc原生機(jī)制,同時(shí)筆者在查看內(nèi)存布局時(shí)觀察到非主分配區(qū)大量heap均為free狀態(tài)。原有機(jī)制是先釋放heap3,如果heap3有內(nèi)存在使用,盡管heap0、heap1、heap2的內(nèi)存都釋放了,那也是無(wú)法釋放給系統(tǒng)。

glibc有多個(gè)分配區(qū),每個(gè)分配區(qū)都幾百 M 空閑內(nèi)存的話,則整個(gè)進(jìn)程占用達(dá)到幾十個(gè)G也就不奇怪了。

3

Glibc內(nèi)存站崗解決方法及patch

在內(nèi)存釋放時(shí),對(duì)于主分配區(qū)和非主分配其走的流程是不一樣的,我們64位系統(tǒng)的進(jìn)程內(nèi)存模型為經(jīng)典模式,棧是從高地址向低地址生長(zhǎng)的。

對(duì)于主分配區(qū)的內(nèi)存站崗我還沒(méi)有遇到過(guò),若主分配區(qū)內(nèi)存站崗,一種方法是可以嘗試madvise將主分配區(qū)的pagesize對(duì)齊的空閑內(nèi)存進(jìn)行釋放,但是這樣效果可能不太明顯。

另外一種是通過(guò)創(chuàng)建線程,然后將主線程的業(yè)務(wù)移到新線程即可,這樣主分配區(qū)就不會(huì)造成站崗了,而將站崗轉(zhuǎn)移到了非主配區(qū),而非主分配區(qū)則是我們接下來(lái)要進(jìn)行優(yōu)化的主戰(zhàn)場(chǎng)。

針對(duì)非主分配區(qū)進(jìn)行兩處優(yōu)化:a) heap0,heap1,heap2是空閑的,那么我們就可以將heap1,heap2釋放掉;b) heap默認(rèn)是64M,降低每個(gè)heap的size(筆者測(cè)試時(shí)設(shè)置為512K)。

這里需要特別解釋一下為什么不釋放heap0和最后一個(gè)heap3,heap0的組成如圖7所示。圖左邊是第一個(gè)heap即heap0,圖右邊是最后一個(gè)heap即heap3。

從圖中可以清晰的看到如若釋放掉heap0那么會(huì)將struct malloc_state結(jié)構(gòu)體釋放,會(huì)造成進(jìn)程崩潰。右邊這個(gè)由于有在用的內(nèi)存,也不能釋放掉。當(dāng)然如果heap3的內(nèi)存全部被釋放了,則由glibc原生代碼進(jìn)行了處理,patch不再處理。

經(jīng)過(guò)修改glibc源碼,優(yōu)化其釋放機(jī)制,實(shí)際打流測(cè)試。

在打流到峰值后,進(jìn)程使用了20G的內(nèi)存,在停止打流后數(shù)秒內(nèi)便恢復(fù)到了打流前的內(nèi)存水平,進(jìn)程所占用的內(nèi)存基本還給系統(tǒng)了。至此,glibc內(nèi)存站崗問(wèn)題得到解決。

以上我們介紹了如何解決內(nèi)存站崗的原理,紙上得來(lái)終覺(jué)淺,現(xiàn)在我們看patch源碼實(shí)現(xiàn)。

目前筆者已經(jīng)將該優(yōu)化的patch提交到開源社區(qū)審核,提交到社區(qū)的patch未對(duì)heap的size進(jìn)行修改,這是因?yàn)橄胍?jǐn)慎一些,畢竟開源的代碼使用場(chǎng)景較多,如有需要可自行決定heap的size。

Patch基于glibc2.17代碼

1. Index: arena.c2. ===================================================================3. --- arena.c (revision 2)4. +++ arena.c (working copy)5. @@ -652,7 +652,7 @@6.7. static int8. internal_function9. -heap_trim(heap_info *heap, size_t pad)10. +heap_trim(heap_info *heap, heap_info* free_heap, size_t pad)11. {12. mstate ar_ptr = heap-》ar_ptr;13. unsigned long pagesz = GLRO(dl_pagesize);14. @@ -659,7 +659,29 @@15. mchunkptr top_chunk = top(ar_ptr), p, bck, fwd;16. heap_info *prev_heap;17. long new_size, top_size, extra, prev_size, misalign;18. + heap_info *last_heap;19.20. + /*Release heap if possible*/21. + last_heap = heap_for_ptr(top_chunk);22. + if ((NULL != free_heap-》prev) && (last_heap != free_heap)){23. + p = chunk_at_offset(free_heap, sizeof(*free_heap));24. + if (!inuse(p)){25. + if (chunksize(p)+sizeof(*free_heap)+MINSIZE==free_heap-》size){26. + while (last_heap){27. + if (last_heap-》prev == free_heap){28. + last_heap-》prev == free_heap-》prev;29. + break;30. + }31. + last_heap = last_heap-》prev;32. + }33. + ar_ptr-》system_mem -= free_heap-》size;34. + arena_mem -= free_heap-》size;35. + unlink(p, bck, fwd);36. + delete_heap(free_heap);37. + return 1;38. + }39. + }40. + }41. /* Can this heap go away completely? */42. while(top_chunk == chunk_at_offset(heap, sizeof(*heap))) {43. prev_heap = heap-》prev;44. Index: malloc.c45. ===================================================================46. --- malloc.c (revision 2)47. +++ malloc.c (working copy)48. @@ -915,7 +915,7 @@49. # if __WORDSIZE == 3250. # define DEFAULT_MMAP_THRESHOLD_MAX (512 * 1024)51. # else52. -# define DEFAULT_MMAP_THRESHOLD_MAX (4 * 1024 * 1024 * sizeof(long))53. +# define DEFAULT_MMAP_THRESHOLD_MAX (256 * 1024)54. # endif55. #endif56.57. @@ -3984,7 +3984,7 @@58. heap_info *heap = heap_for_ptr(top(av));59.60. assert(heap-》ar_ptr == av);61. - heap_trim(heap, mp_.top_pad);62. + heap_trim(heap, heap_for_ptr(p), mp_.top_pad);63. }64. }

4

結(jié)束語(yǔ)

不同的內(nèi)存管理方式均有其優(yōu)勢(shì)和缺陷,由于工作需要,筆者有幸研究過(guò)glibc、tcmalloc、uclibc內(nèi)存管理,本文討論了glibc內(nèi)存管理存在的一個(gè)共性問(wèn)題,并給出可行的解決方案。

對(duì)于內(nèi)存站崗問(wèn)題,一般的做法是用戶自己緩存一些長(zhǎng)時(shí)間不釋放的內(nèi)存。另一種是干脆將glibc替換為tcmalloc。因?yàn)?tcmalloc 的 span比較小,所以站崗發(fā)生的概率極低,即便發(fā)生也就站崗一個(gè)span的大小。若由于某些原因不能用tcmalloc代替glibc的場(chǎng)景,如上的解決思路可以嘗試一下,該問(wèn)題也困擾我們多時(shí)了,花費(fèi)了較長(zhǎng)時(shí)間和較多精力去定位。

在glibc2.28的版本中,glibc有了tcache的特性,對(duì)于業(yè)務(wù)進(jìn)程使用大量小內(nèi)存的場(chǎng)景則更加容易出現(xiàn)內(nèi)存站崗問(wèn)題。在撰寫本文時(shí)查看了glibc2.33版本,開源社區(qū)還未對(duì)該問(wèn)題進(jìn)行修改(或許是開源社區(qū)大神認(rèn)為這不是glibc的問(wèn)題,而是用戶不釋放內(nèi)存)。

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11746

    瀏覽量

    218902
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4965

    瀏覽量

    73844
  • Glibc
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    7742

原文標(biāo)題:Linux glibc 內(nèi)存站崗問(wèn)題及解決方法

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    C編譯器錯(cuò)誤與解決方法

    C語(yǔ)言keil編譯器提示錯(cuò)誤的解決方法,可以幫你解決程序編譯中的煩惱!! C編譯器錯(cuò)誤與解決方法 1. Warning 280:’i’:unreferenced local variable
    發(fā)表于 01-22 08:03

    ODF配線架常見故障及解決方法

    ODF配線架常見故障及解決方法如下: 一、接地故障 故障表現(xiàn): 防雷性能下降,靜電積累,甚至引發(fā)設(shè)備損壞。 光信號(hào)傳輸不穩(wěn)定,出現(xiàn)誤碼或中斷。 常見原因: 接地端子氧化、松動(dòng)或接觸不良。 接地線
    的頭像 發(fā)表于 01-05 10:43 ?288次閱讀

    請(qǐng)問(wèn)C語(yǔ)言中整形溢出的解決方法有哪些?

    C語(yǔ)言中整形溢出的解決方法有哪些?
    發(fā)表于 12-29 07:33

    rk基于linux/android內(nèi)存管理

    一、內(nèi)存分布 ? U-Boot 由前級(jí) Loader 加載到 CONFIG_SYS_TEXT_BASE 地址,初始化時(shí)會(huì)探明當(dāng)前系統(tǒng)的總內(nèi)存容 量, 32 位平臺(tái)上認(rèn)為最大 4GB 可用(但是不影響
    的頭像 發(fā)表于 12-15 10:42 ?180次閱讀
    rk基于linux/android<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>

    MCU調(diào)試典型問(wèn)題與解決方法

    ;CFSR(故障狀態(tài)寄存器)、SCB->HFSR、SCB->MMFAR(內(nèi)存管理地址)。 使用ARM Cortex-M的故障診斷庫(kù)(如CmBacktrace)自動(dòng)定位崩潰代碼行。
    發(fā)表于 11-17 07:57

    Vivado仿真之后沒(méi)有出現(xiàn)仿真結(jié)果的解決方法

    ;Run Behavioral Simulation之后,會(huì)出現(xiàn)如下圖界面,此時(shí),在Tcl Console中并沒(méi)有出現(xiàn)仿真結(jié)果。 沒(méi)有出現(xiàn)仿真結(jié)果的原因是沒(méi)有給Vivado時(shí)間進(jìn)行仿真,解決方法
    發(fā)表于 10-31 06:24

    程序加載過(guò)程中遇到的問(wèn)題及其解決方法

    /quick_start/ide.html。 (1)遇到的問(wèn)題1:在創(chuàng)建好項(xiàng)目后,運(yùn)行配置設(shè)置為ILM,可以編譯成功;當(dāng)修改運(yùn)行配置為Flash后,編譯失?。恢貑④浖?,仍會(huì)遇到類似問(wèn)題。 解決方法
    發(fā)表于 10-30 07:59

    LVDS接口的顯示屏,顯示偏暗問(wèn)題的解決方法

    問(wèn)題:點(diǎn)亮屏幕后畫面顯示偏暗 可能原因: 主板輸出的LVDS 模式與屏幕的不一致; PWM亮度并未調(diào)節(jié)到最亮; 解決方法 檢查主板的LVDS輸出模式是否和屏幕一致; 一般主板端的LVDS模式是可以配置的,配置成與屏幕相同的模式即可; 檢查PWM亮度調(diào)節(jié)是否正常?或者直接給高電平測(cè)試;
    發(fā)表于 10-09 15:55

    國(guó)產(chǎn)主板無(wú)法開機(jī)的狀況及解決方法

    在計(jì)算機(jī)的硬件系統(tǒng)中,主板作為連接各個(gè)組件的關(guān)鍵樞紐,其穩(wěn)定運(yùn)行至關(guān)重要。隨著國(guó)產(chǎn)主板技術(shù)的不斷發(fā)展與普及,了解其常見故障及解決方法,能幫助用戶在遇到問(wèn)題時(shí)快速排查修復(fù),保障計(jì)算機(jī)正常使用。
    的頭像 發(fā)表于 07-02 09:33 ?1236次閱讀
    國(guó)產(chǎn)主板無(wú)法開機(jī)的狀況及<b class='flag-5'>解決方法</b>

    電機(jī)常見的噪音、振動(dòng)問(wèn)題及解決方法

    ,甚至引發(fā)安全隱患。本文將系統(tǒng)分析電機(jī)常見的噪音和振動(dòng)問(wèn)題,并提供切實(shí)可行的解決方法。 ? 一、電機(jī)噪音問(wèn)題及解決方法 電機(jī)噪音主要來(lái)源于電磁噪音、機(jī)械噪音和空氣動(dòng)力噪音三個(gè)方面。 1. 電磁噪音 電磁噪音是由于電機(jī)內(nèi)部
    的頭像 發(fā)表于 06-08 10:25 ?3406次閱讀

    電機(jī)常見故障分析及解決方法

    電機(jī)在運(yùn)行過(guò)程中可能會(huì)出現(xiàn)多種故障,以下是一些常見故障的分析及解決方法: 一、機(jī)械故障 1. 軸承損壞或磨損 ? ?● 故障表現(xiàn):電機(jī)運(yùn)轉(zhuǎn)不平穩(wěn),產(chǎn)生異響,嚴(yán)重時(shí)甚至停轉(zhuǎn)。 ? ?● 原因分析:通常
    的頭像 發(fā)表于 04-25 15:20 ?5397次閱讀
    電機(jī)常見故障分析及<b class='flag-5'>解決方法</b>

    SMT加工虛焊大揭秘:判斷與解決方法全攻略

    Solder Joint)問(wèn)題可能會(huì)導(dǎo)致電子設(shè)備無(wú)法正常工作,甚至引發(fā)長(zhǎng)期可靠性問(wèn)題。因此,準(zhǔn)確判斷和有效解決SMT加工中的虛焊問(wèn)題對(duì)保證產(chǎn)品質(zhì)量至關(guān)重要。 SMT加工虛焊的判斷與解決方法 什么是SMT加工虛焊? 虛焊是指焊點(diǎn)表面看似完好,但內(nèi)部沒(méi)有形成牢固的電氣連接,
    的頭像 發(fā)表于 03-18 09:34 ?1761次閱讀

    如何解決錫膏焊錫后存在的毛刺和玷污問(wèn)題?

    錫膏焊錫后存在的毛刺和玷污問(wèn)題,可能由多種因素引起,以下是一些具體的解決方法
    的頭像 發(fā)表于 03-14 09:10 ?786次閱讀
    如何解決錫膏焊錫后<b class='flag-5'>存在</b>的毛刺和玷污問(wèn)題?

    321Y驅(qū)動(dòng)器的常見故障及解決方法

    ? 321Y驅(qū)動(dòng)器常見故障及解決方法 ?: ? 過(guò)載故障 ? ? 現(xiàn)象 ?:驅(qū)動(dòng)器連續(xù)使用超過(guò)額定負(fù)載兩倍時(shí),會(huì)產(chǎn)生異常警報(bào)?1。 ? 解決方法 ?:降低負(fù)載、調(diào)整減速箱傳動(dòng)比、增加電動(dòng)機(jī)容量等?1
    的頭像 發(fā)表于 03-07 15:50 ?1706次閱讀

    IGBT在中頻電源中常見的故障模式及解決方法

    在現(xiàn)代工業(yè)電氣領(lǐng)域,中頻電源應(yīng)用廣泛,而 IGBT(絕緣柵雙極型晶體管)作為中頻電源的核心器件,起著至關(guān)重要的作用。本文將深入探討 IGBT 在中頻電源中的工作原理、關(guān)鍵作用,以及常見的故障模式及解決方法。
    的頭像 發(fā)表于 03-03 14:16 ?2963次閱讀
    IGBT在中頻電源中常見的故障模式及<b class='flag-5'>解決方法</b>