python 源碼筆記 ---- freeblock

1 引言
python

在python內存管理中,有一個block的概念。它比較相似於SGI次級空間配置器。
首先申請一塊大的空間(4KB),而後把它切割成一小份(8, 16 一直到512)。
當有內存申請的請求時候,簡單的流程是:根據大小找到對應的block,而後在freeblock 上給它一份。spa

2 問題指針

整個過程是一種比較天然的slab分配方式。但當我讀到這段代碼時,卻感到疑惑:code

static void* _PyObject_Malloc(void* ctx, size_t nbytes)
{
        ...
    pool->freeblock = (block*)pool +  pool->nextoffset;

        pool->nextoffset += INDEX2SIZE(size);
        *(block **)(pool->freeblock) = NULL; // [1]
        ...
}

freeblock指向空閒的鏈表,爲它賦值很好理解。可是爲何要加上代碼1處那一句!
對C比較熟悉的童鞋很容易能看出它的做用,它在爲*freeblock賦值爲NULL。blog

可是爲何要這麼作?
直到看到內存回收的代碼:索引

static void _PyObject_Free(void* ctx, void*p)
{
    ...
    *(block**)p = lastfree = pool->freeblock;
    pool->freeblock = (block*)p;
    ...
}

回想一下SGI次級空間配置,它須要一個鏈表,指向block中可用的小塊。由於這些快,是離散的,只有用指針才能索引它。
在SGI次級空間配置中,是用一個union,達到了節省空間的目的:有數據時,它存儲着真正的數據;沒有數據時,它就變成指向下一塊可用內存的指針:圖片

union __Obj {
    union __Obj* free_list_link;
    char client_data[];
};

這樣一想,問題就變得很明顯了。freeblock指向一個鏈表,鏈表的next域就由它本身來索引。
在_PyObject_Free中,內存p是要被回收的,它應該插在freeblock的鏈表頭,freeblock被更新指向它。同時,p指向原來freeblock指向的內容,這是一個很簡單的鏈表插入操做。
這樣在遍歷的時候,咱們就能夠用freeblock = * freeblock的方式來工做了。
以下圖所示:內存

圖片描述

相關文章
相關標籤/搜索