再記malloc/free

之前寫過一篇博文,介紹當free()掉與malloc()返回指針不一致時導致崩潰原因:http://liulixiaoyao.blog.51cto.com/1361095/565677

這篇博文裏面解釋了崩潰是緣於指針變化之後,定位不到正確的內存管理頭部導致;

今天想到一個問題,對於棧上的指針,指針的值是變量的地址,比如10元素的數組,可以直接通過p+i的方式訪問,那對於堆上分配的內存,同樣是malloc(10*sizeof(int)),由於前面或者某處需要一個管理頭部對該內存塊進行管理,malloc得到的指針指向的內存在哪兒?

如果指向管理頭部,用p+i的方式明顯會出錯,則在堆和棧上兩種指針操作會表現出不同結果,這如何可以?

要想兩者表現一直,malloc返回的結果所指向的內存區域不包含管理頭部的區域,但是可以通過固定的運算方式,找到管理頭部的所在,這個操作由glibc在調用free()的時候進行

事實證明的確如此,free函數的源碼大致如下:

  1. void free(void *ptr)    
  2.    {   
  3.            struct mem_control_block *free;   
  4.            free = ptr - sizeof(struct mem_control_block);   
  5.            free->is_available = 1;   
  6.            return;   
  7.    } 

管理頭部的結構體定義如下:

  1. struct mem_control_block {   
  2.  int is_available;     
  3.  int size;             
  4.  }; 

如源碼所示,可猜測malloc返回的指針指向實際可使用的內存地址,實際分配的內存塊要大於請求的size(多出管理頭部);free之時通過減去管理頭部大小可獲得實際分配的內存塊,可解決上面的疑慮

 

接下來又引出另外一個問題,在free函數中,我們並沒有看見實際的內存釋放函數的調用(當然這時候釋放必然不是調用free,free只是由glibc實現的包裝),只有 free->is_available = 1;   這句有點實際意義,那內存在什麼時機被釋放呢?

有網友說是,is_avaliable是個標記,指示該塊內存可被釋放,已沒有人使用,後續的釋放操作由操作系統定時掃描,釋放掉不再使用的內存塊

is_avaliable是標記之用,的確沒錯,是顯而易見的事情,至於實際的內存釋放由操作系統定時掃描釋放,卻並不見得如此;

記得曾經瞭解到,glibc的malloc的實現,也是有預分配策略的,請求10字節,可能會分配100字節甚至更多(具體策略未詳),這裏的分配釋放應該都是由glibc庫管理的,應該清楚,glibc是用戶空間代碼,用戶空間代碼分配的內存是不會由操作系統釋放的,操作系統定期會掃描釋放內存不錯,不過那應該是針對內核級別的,比如slab,文件系統page頁面緩存等使用了預分配策略的,用戶空間已使用系統調用brk等進行分配的內存空間對內核來說是實際被使用中的,不可能被內核回收

 

另,記錄一下,malloc衆所周知是在堆上分配內存,堆的空間是可以申請調大的;貌似記得malloc分配的空間也可能不是來自於堆,有可能是mmap的區域,描述可能不準,有待查證,僅作記錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章