在swoole_init()
中執行了這麼一句SwooleG.memory_pool = swMemoryGlobal_new(SW_GLOBAL_MEMORY_PAGESIZE, 1);
會返回一個swMemoryPool
的”介面實現“。這部分內容屬於記憶體管理。
typedef struct _swMemoryPool
{
void *object;
void* (*alloc)(struct _swMemoryPool *pool, uint32_t size);
void (*free)(struct _swMemoryPool *pool, void *ptr);
void (*destroy)(struct _swMemoryPool *pool);
} swMemoryPool;
swMemoryPool
結構以指標的形式來表現“介面”。下面看swMemoryGlobal
的具體實現。首先看結構定義
typedef struct _swMemoryGlobal_page
{
struct _swMemoryGlobal_page *next; //下一個page
char memory[0]; //柔性陣列,指向申請的記憶體地址
} swMemoryGlobal_page;
typedef struct _swMemoryGlobal
{
uint8_t shared;
uint32_t pagesize; //每頁大小
swLock lock;
swMemoryGlobal_page *root_page; //根節點
swMemoryGlobal_page *current_page; //尾節點
uint32_t current_offset; //尾節點資料偏移量
} swMemoryGlobal;
很明顯是以連結串列的形式來組織的。看新建swMemoryGlobal
swMemoryPool* swMemoryGlobal_new(uint32_t pagesize, uint8_t shared)
{
swMemoryGlobal gm, *gm_ptr;
assert(pagesize >= SW_MIN_PAGE_SIZE);
bzero(&gm, sizeof(swMemoryGlobal));
gm.shared = shared;
gm.pagesize = pagesize;
swMemoryGlobal_page *page = swMemoryGlobal_new_page(&gm);
if (page == NULL)
{
return NULL;
}
if (swMutex_create(&gm.lock, shared) < 0)
{
return NULL;
}
gm.root_page = page;
gm_ptr = (swMemoryGlobal *) page->memory;
gm.current_offset += sizeof(swMemoryGlobal);
swMemoryPool *allocator = (swMemoryPool *) (page->memory + gm.current_offset);
gm.current_offset += sizeof(swMemoryPool);
allocator->object = gm_ptr;
allocator->alloc = swMemoryGlobal_alloc;
allocator->destroy = swMemoryGlobal_destroy;
allocator->free = swMemoryGlobal_free;
memcpy(gm_ptr, &gm, sizeof(gm));
return allocator;
}
static swMemoryGlobal_page* swMemoryGlobal_new_page(swMemoryGlobal *gm)
{
swMemoryGlobal_page *page = (gm->shared == 1) ? sw_shm_malloc(gm->pagesize) : sw_malloc(gm->pagesize);
if (page == NULL)
{
return NULL;
}
bzero(page, gm->pagesize);
page->next = NULL;
if (gm->current_page != NULL)
{
gm->current_page->next = page;
}
gm->current_page = page;
gm->current_offset = 0;
return page;
}
在新建頁中,主要是申請記憶體,做一個連結串列的處理,其中需要注意的是。在swMemoryGlobal
中需要注意的是current_offset
的偏移量是sizeof(swMemoryPool)+sizeof(swMemoryPool)
,也就是說明swMemoryPool
和swMemoryPool
的資訊儲存在page裡。
接下來看3個函式
static void *swMemoryGlobal_alloc(swMemoryPool *pool, uint32_t size)
{
swMemoryGlobal *gm = pool->object;
size = SW_MEM_ALIGNED_SIZE(size);
gm->lock.lock(&gm->lock);
if (size > gm->pagesize - sizeof(swMemoryGlobal_page))
{
swWarn("failed to alloc %d bytes, exceed the maximum size[%d]", size, gm->pagesize - (int) sizeof(swMemoryGlobal_page));
gm->lock.unlock(&gm->lock);
return NULL;
}
if (gm->current_offset + size > gm->pagesize - sizeof(swMemoryGlobal_page))
{
swMemoryGlobal_page *page = swMemoryGlobal_new_page(gm);
if (page == NULL)
{
swWarn("swMemoryGlobal_alloc alloc memory error");
gm->lock.unlock(&gm->lock);
return NULL;
}
gm->current_page = page;
}
void *mem = gm->current_page->memory + gm->current_offset;
gm->current_offset += size;
gm->lock.unlock(&gm->lock);
return mem;
}
static void swMemoryGlobal_free(swMemoryPool *pool, void *ptr)
{
swWarn("swMemoryGlobal Allocator don't need to release");
}
static void swMemoryGlobal_destroy(swMemoryPool *poll)
{
swMemoryGlobal *gm = poll->object;
swMemoryGlobal_page *page = gm->root_page;
swMemoryGlobal_page *next;
do
{
next = page->next;
sw_shm_free(page);
page = next;
} while (page);
}
不需要free、destroy從連結串列頭依此釋放記憶體。
alloc的規則也很簡單:a.申請的size超過規定,不給分配。 b.當前page剩餘量不夠,申請新個page來分配 c.當前page夠用,直接分配。
還有兩種記憶體分配,ring_buffer和fixed_pool,用到再說。