日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

glibc(ptmalloc)内存暴增问题解决

發布時間:2025/7/25 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 glibc(ptmalloc)内存暴增问题解决 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

from:http://blog.chinaunix.net/uid-18770639-id-3385860.html


點擊(此處)折疊或打開

  • #include <stdio.h>
  • #include <stdlib.h>
  • #include <string.h>

  • int main()
  • {
  • ????int alloc_time = 4000;
  • ????char *a[alloc_time];
  • ????char *b[alloc_time];

  • ????int i, j;
  • ????for(i=0; i<alloc_time; i++)
  • ????{
  • ????????a[i] = (char *)malloc(52722);
  • ????????memset(a[i], 1, 52722);
  • ????????b[i] = (char *)malloc(1);
  • ????????memset(b[i], 1, 1);
  • ????}
  • ????printf("malloc finished\n");
  • ????for(i=alloc_time-1; i>=0; i--)
  • ????{
  • ????????free(a[i]);
  • ????????free(b[i]);
  • ????}
  • ????printf("free finished\n");
  • ????//char *p = (char *)malloc(2000);
  • ????//free(p);

  • ????while(1){
  • ????????sleep(3);
  • ????}
  • }

  • 運行這個測試程序,發現Glibc內存暴增,程序已經把內存返回給了Glibc庫,但Glibc庫卻沒有把內存歸還給操作系統。

    分析:

    ptmalloc使用chunk結構來實現內存管理。用戶free掉的內存并不是都會馬上歸還給系統,ptmalloc會統一管理heap和mmap映射區域中的空閑chunk。當用戶進行下一次分配請求時,ptmalloc會首先試圖在空閑的chunk中挑選一塊給用戶,這樣就避免了頻繁的系統調用,降低了內存分配的開銷。對于空閑的chunk,ptmalloc采用分箱式內存管理方式,根據空閑chunk的大小和處于的狀態將其放在三個不同的容器中。

    bins:ptmalloc將相似大小的chunk用雙向鏈表鏈接起來,這樣的一個鏈表被稱為一個bin。bins有128個隊列,前64個隊列是定長的(small bins),每隔8個字節大小的塊分配在一個隊列,后面的64個隊列是不定長的(largebins),就是在一個范圍長度的都分配在一個隊列中。所有長度小于512字節的都分配在定長的隊列中,后面的64個隊列是變長的隊列,每個隊列中的chunk都是從大到小排列的。

    ?unsort隊列(只有一個隊列),它是一個cache,所有free下來的如果要進入bins隊列中都要經過unsort隊列,分配內存時會查看unsorted bin中是否有合適的chunk,如果找到滿足條件的chunk,則直接返回給用戶,否則將unsorted bin中所有chunk放入bins中。

    fastbins,大約有10個定長隊列,它是一個高速緩沖,所有free下來的并且長度是小于max_fast(默認80B)的chunk就會進入這種隊列中。進入此隊列的chunk在free的時候并不修改使用位,目的是為了避免被相鄰的塊合并掉。

    如果內存塊是空閑的,它會掛在其中的一個隊列中,它是通過復用的方式,使用空閑chunk的第3個字和第4個字當作它的前鏈和后鏈(變長塊是第5個字和第6個字)。

    ?

    malloc的步驟:

    1.????????先在fastbins中找,如果能找到,從隊列中取下后(不需要再置使用位為1)立刻返回;

    2.????????判斷需求的塊是否在small bins(bins的前64個bin)范圍,如果在小箱子范圍,并且剛好有滿足需求的塊,則直接返回內存地址;

    3.????????到了這一步,說明需要分配的是一塊大內存,或者小箱子里找不到合適的chunk;這個時候,會觸發consolidate,ptmalloc首先會遍歷fastbins中的chunk,將相鄰的chunk合并,并鏈接到unsorted bin中(因為在大箱子找一般都要切割,所以要優先合并,避免過多碎片);

    4.????????在unsort bin中取出一個chunk,如果能找到剛好和想要的chunk相同大小的chunk,立刻返回,如果不是想要的chunk大小的chunk,就把它插入到bins對應的隊列中去,轉到2。

    5.????????到了這一步,說明需要分配的是一塊大的內存,或者small bins和unsorted bin中都找不到合適的chunk,并且fastbins和unsorted bin中所有的chunk都清楚干凈了。在large bins中找,找到一個最小的能符合需求的chunk從隊列中取下,如果剩下的大小還能建一個chunk,就把chunk分成兩個部分,把剩下的chunk插入到unsort隊列中取,把chunk的內存地址返回;

    6.????????如果搜索fastbins和bins都沒有找到合適的chunk,那么就需要操作topchunk(是堆頂的一個chunk,不會放在任何一個隊列里)來進行分配了。在topchunk找,如果能切出符合要求的,把剩下的一部分當作topchunk,然后返回內存地址;

    7.????????到了這一步說明topchunk也不能滿足分配要求,就只能調用sysalloc,其實就是增長堆了,然后返回內存地址。


    free的步驟:

    1.????????判斷所需釋放的chunk是否為mmapedchunk,如果是,則調用munmap釋放mmaped chunk,解除內存空間映射,該空間不再有效,然后立刻返回;

    2.????????如果和topchunk相鄰,直接和topchunk合并,不會放到其他的空閑隊列中取,然后立刻返回;

    3.????????如果釋放的大小小于max_fast(80字節),就把它掛到fastbins中去返回,使用位仍然為1,當然更不會去合并相鄰塊,然后立刻返回;

    4.????????如果釋放塊得大小介于80—128K,把chunk的使用位置為0,判斷前一個chunk是否處于使用中,如果前一塊也是空閑塊,則合并,并轉入下一步;

    5.????????判斷當前釋放chunk的下一個塊是否為topchunk,如果是,則轉到第7步,否則轉下一步;

    6.????????判斷下一個chunk是否處在使用中,如果也是空閑的,則合并,并將合并后的chunk掛到unsort隊列中去;

    7.????????如果執行到了這一步,說明釋放了一個與top chunk相鄰的chunk;則無論它有多大,都將它與topchunk合并,并更新topchunk的大小等信息,轉下一步;

    8.????????如果合并后的大小大于FASTBIN_CONSOLIDATION_THRESHOLD(64K),也會觸發consolidate,即fastbins的合并操作,合并后的chunk會被放到unsortedbin中,fastbins將變為空,操作完成之后轉下一步;

    9.????????試圖收縮堆。(判斷topchunk的大小是否大于mmap的收縮閾值,默認為128KB)。

    ?

    ptmalloc對于大于128K的塊通過mmap方式來分配,小于128K(mmap分配閾值)的塊在heap中分配。堆是通過brk的方式來增加或壓縮的,如果在現有的堆中不能找到合適的chunk,會通過增長堆的方式來滿足分配,如果堆頂的空閑塊超過一定的閾值會收縮堆,所以只要堆頂的空間沒釋放,堆是一直不會收縮的。因為ptmalloc的內存收縮是從top chunk開始,如果與top chunk(堆頂的一個chunk)相鄰的那個chunk在內存池中沒有釋放,top chunk以下的空閑內存都無法返回給系統,即使這些空閑內存有幾十個G也不行。

    按照這個測試程序分配后,內存變成由小塊和大塊交替出現,釋放小塊的時候,直接把小塊放在fastbins中取,而且他的使用位還是1,釋放大塊的時候,它試圖合并相鄰的塊,但是和它相鄰的塊的使用位還是1,所以它不能把相鄰的塊合并起來,而且釋放的塊的大小小于64K,也不會觸發consolidate,即不會把fastbins清空,所以當所有的塊都被釋放完后,所有的小塊都在fastbins里面,使用位都還是1,大塊都掛在unsort隊列里面。全部都無法合并。所以使用的堆更加無法壓縮。如果在循環后面再分配2000字節然后釋放的話,所有內存將全部被清空,這是因為再申請2000字節的時候,由malloc的第二步,程序會先調用consolidate,即把所有的fastbins清空,同時把相鄰的塊合并起來,等到所有的fastbins清空的時候,所有的塊也被合并起來了,然后調用free(2000)的時候,這塊將被合并起來,成為topchunk,并且大小遠小于64K,所有堆將會壓縮,內存歸還給系統。

    ?

    解決方法:

    減小mmap分配閾值,對于大內存塊分配盡量采用mamp系統調用直接向操作系統分配,回收時用munmap返回給操作系統。但是這種做法會降低ptmalloc的分配釋放效率,因為系統調用mamp是串行的,操作系統需要對mmap分配內存加鎖,而且操作系統對mmap的物理頁強制清0很慢。
    這個可以通過修改 MALLOC_MMAP_THRESHOLD_環境變量或者調用mallopt()接口來實現。

    總結

    以上是生活随笔為你收集整理的glibc(ptmalloc)内存暴增问题解决的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。