ptmalloc原始碼閱讀 malloc chunk

2021-07-09 12:39:48 字數 3343 閱讀 1206

記憶體管理不外乎三個層面,使用者管理層,c執行時庫層,作業系統層

目前輪子處於執行時庫層,製作這個輪子的目的是為了了解底層記憶體分配是如何實現的,後面肯定主要是實現使用者管理層。

常見c記憶體管理程式:

doug lea malloc:doug lea malloc實際上是完整的一組分配程式,其中包括doug lea的原始分配程式,gnu libc分配程式和ptmalloc。doug lea的分配程式加入了索引,這使得搜尋速度更快,並且可以將多個沒有被使用的塊組合為乙個大的塊。它還支援快取,以便更快地再次使用最近釋放的記憶體。ptmalloc是doug lea malloc 的乙個擴充套件版本,支援多執行緒。在本文後面的部分詳細分析ptamlloc2的源**實現。

bsd malloc:bsd malloc是隨4.2 bsd發行的實現,包含在freebsd之中,這個分配程式可以從預先確實大小的物件構成的池中分配物件。它有一些用於物件大小的 size類,這些物件的大小為2的若干次冪減去某一常數。所以,如果您請求給定大小的乙個物件,它就簡單地分配乙個與之匹配的size類。這樣就提供了乙個快速的實現,但是可能會浪費記憶體。

hoard:編寫hoard的目標是使記憶體分配在多執行緒環境中進行得非常快。因此,它的構造以鎖的使用為中心,從而使所有程序不必等待分配記憶體。它可以顯著地加快那些進行很多分配和**的多執行緒程序的速度。

tcmalloc:(thread-caching malloc)是google開發的開源工具──「google-perftools」中的成員

目前主要通過閱讀gnu的libc的ptmalloc來學習主流的記憶體管理

malloc_chunk

struct malloc_chunk ;glibc原始碼中有colin plumb作出的很詳細的介紹。chunk的使用採用了乙個「boundary tag」的方法重點理解chunk的復用。

乙個空閒的塊的儲存結構如下:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| size of previous chunk|

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`head:' | size of chunk, in bytes |p|

mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| forward pointer to next chunk in list |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| back pointer to previous chunk in list|

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| unused space (may be 0 bytes long).

. .

. |

nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

`foot:' | size of chunk, in bytes |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

每個free的chunk都是儲存在乙個雙向鍊錶,而所有的雙向鍊錶都儲存在bin中,所以mem中會儲存fp和bp。而每個chunk的開頭會儲存前乙個free的chunk的size,緊接著的head會儲存chunk的大小,但是最後一位p表示前面乙個chunk是否被使用,置0表示沒被使用。第一次分配是該位置1。

如果p位置1,則表示前乙個chunk被使用了,則size of previou chunk沒有任何意義,反而可以被前乙個chunk利用來儲存資料。fp和bp同樣被復用。

則儲存內容的塊的結構如下:

chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| size of previous chunk, if allocated| |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| size of chunk, in bytes |m|p|

mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| user data starts here... .

. .

. (malloc_usable_size() bytes) .

. |

nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| size of chunk |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

在開始有乙個宣告(對size_t的處理):

#ifndef internal_size_t

#define internal_size_t size_t

#endif

.../* the corresponding word size */

#define size_sz (sizeof(internal_size_t))

...

struct malloc_chunk;

typedef struct malloc_chunk* mchunkptr;

緊接著 後面一塊內容是對塊的size和對齊的一系列處理:

因為malloc之後返回的指標為mem的起始位址,所以有對該位址與chunk位址的轉換,由上面的結構表示可以明白下面的處理:

#define chunk2mem(p)   ((void*)((char*)(p) + 2*size_sz))

#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*size_sz))

每個chunk最小的大小:

#define min_chunk_size(offsetof(struct malloc_chunk, fd_nextsize))
其中

#define offsetof(s, m)   (size_t)&(((s *)0)->m)
s是乙個結構名,它有乙個名為m的成員(s和m 是巨集offsetof的形參,它實際是返回結構s的成員m的偏移位址.(s )0 是騙編譯器說有乙個指向類(或結構)s的指標,其位址值0。&((s )0)->m 是要取得類s中成員變數m的位址. 因基址為0,這時m的位址當然就是m在s中的偏移。最後轉換size_t 型。

後面還有一些處理不細講了,原始碼中都有很詳細的注釋。重點是要了解chunk的資料結構以及記憶體復用的思想。

《原始碼閱讀》原始碼閱讀技巧,原始碼閱讀工具

檢視某個類的完整繼承關係 選中類的名稱,然後按f4 quick type hierarchy quick type hierarchy可以顯示出類的繼承結構,包括它的父類和子類 supertype hierarchy supertype hierarchy可以顯示出類的繼承和實現結構,包括它的父類和...

原始碼閱讀 Glide原始碼閱讀之with方法(一)

前言 本篇基於4.8.0版本 原始碼閱讀 glide原始碼閱讀之with方法 一 原始碼閱讀 glide原始碼閱讀之load方法 二 原始碼閱讀 glide原始碼閱讀之into方法 三 大多數情況下,我們使用glide 就一句 但是這一句 裡面蘊含著成噸的 with方法有以下幾個過載方法 publi...

原始碼閱讀 Glide原始碼閱讀之load方法(二)

原始碼閱讀 glide原始碼閱讀之load方法 二 原始碼閱讀 glide原始碼閱讀之into方法 三 首先,load方法有以下幾個過載方法 public requestbuilder load nullable bitmap bitmap public requestbuilder load nu...