pg的内存管理机制一:AllocSet的内存分配

1 AllocSet 的内存分配涉及到的方法和数据结构

话说

MemoryContextMethods 结构里的函数实现了pgAllocSetMemoryContext 的内存管理机制,定义见下面。

 

 

typedef struct MemoryContextMethods

{

     void    *(*alloc) (MemoryContext context, Size size);

     /* call this free_p in case someone #define's free() */

     void      (*free_p) (MemoryContext context, void *pointer);

     void    *(*realloc) (MemoryContext context, void *pointer, Size size);

     void      (*init) (MemoryContext context);

     void      (*reset) (MemoryContext context);

     void      (*delete ) (MemoryContext context);

     Size     (*get_chunk_space) (MemoryContext context, void *pointer);

     bool      (*is_empty) (MemoryContext context);

     void      (*stats) (MemoryContext context);

#ifdef MEMORY_CONTEXT_CHECKING

     void      (*check) (MemoryContext context);

#endif

} MemoryContextMethods;

 

 

 

 

 

 

 

其中alloc 由静态函数AllocSetAlloc() 实现,具体签名在下面。它实现了AllocSet 相关的内存分配机制。

static void * AllocSetAlloc(MemoryContext context, Size size)

在写AllocSet 内存分配机制之前,先看两个和内存分配与管理密切相关的结构 Allockblock AllockChunk ,这个 前面的文章http://beigang.iteye.com/blog/1266554和http://beigang.iteye.com/blog/1279177里已经 提到不 止一次了。

    Allockblock AllockChunk 都是内存里的块,AllockBlock 类型是AllockBlockData *AllocChunk 类型是AllockChunkData*AllocBlockAllocSetmalloc 分配的内存单元,包含着一到多个AllockChunkAllocChunk是 MemoryContextMethods.alloc 请求分配的内存单元,将来由MemoryContextMethods . free_p 释放,放到AllocSetfreelist 链表数组的大小合适的链表里,以后被MemoryContextMethods.alloc 再分配。

AllockBlockData AllockChunkData 的定义如下

 

 

 

 

 

typedef struct AllocBlockData

{

    AllocSet    aset;           /* aset that owns this block */

    AllocBlock  next;           /* next block in aset's blocks list */

    char        *freeptr;        /* start of free space in this block */

    char        *endptr;         /* end of space in this block */

} AllocBlockData;

 

typedef struct AllocChunkData

{

    /* aset is the owning aset if allocated, or the freelist link if free */

    void        *aset;

    /* size is always the size of the usable space in the chunk */

    Size        size;

#ifdef MEMORY_CONTEXT_CHECKING

    /* when debugging memory usage, also store actual requested size */

    /* this is zero in a free chunk */

    Size        requested_size;

#endif

} AllocChunkData;

 

2 AllocSetAlloc

下面就写 MemoryContextMethods.alloc 的实现者AllocSetAlloc() 这个函数。这个内存分配过程还是有点复杂的,下面先上个图,然后分块解读处理流程。

 


pg的内存管理机制一:AllocSet的内存分配_第1张图片

 

 

 

 

AllocSetAlloc 分配内存流程图

 

 

 

 

 

 

根据上面的图,按红紫蓝黄绿的顺序做简要分解,具体的还是看流程图吧,算法基本上都在图里面了。

先声明一点,TopMemoryContext 所用内存是用malloc 独立分的,其他的AllocSet 都是调用AllocSetAlloc 分得。

现在分解红色块。首先传进来要在其上分配内存的AllocSet 和请求的大小,如果请求大小没有超过AllocChunk 的最大大小8k ,就在该AllocSet 的空闲可用AllocChunk 链表数组freelist (后面分析这个freelist )合适大小的链表里找有没有可以使用的AllocChunk ,如果没有的话就把请求大小加上AllocChunk 的大小(图中的Q ),然后在AllocSetAllocBlock 链表blocks 里找,看blocks 有没有满足大小的可用block ,如果没有,就malloc 分配一块block 。红色块到此结束。

接下来是紫色块,在上面分配的block 里分一个AllocChunk ,然后把该chunk 作为MemoryContext 类型返回,至此就分得了一块内存。

    蓝色框里是如果请求的大小超过了AllocChunk 的最大值8k ,就malloc 分配一个请求大小的block ,将其加入AllockSetblocks 链表中。在这个block 里面分配一个chunk ,作为MemoryContext 类型返回。

    黄色框里是如果前面在AllocSetfreelist 链表数组中的合适的链表里找到了可用chunk ,就把该chunk 从链表中取出来,作为MemoryContext 类型返回。

    现在就剩绿色框了。绿色框是维护前面多次提到的freelist 链表数组的,现在是分析这个空闲AllocChunk 链表数组的时候了。先看这个freelistAllocSet 可分配的AllocChunk 的大小是从23 次方依次到213 次方字节,也就是从8 字节依次到8k 字节。这样做的好处是可以方便管理内存,要是按实际需求分配的话对于内存再分配是个很大的挑战,会造成内存浪费。结构图见下面。


pg的内存管理机制一:AllocSet的内存分配_第2张图片

AllocSet freelist 结构图

    绿色框里就是说如果在AllocSetAllocBlock 链表blocks 里找到了block ,但是该block 的可用空闲空间不够请求大小时就把空闲大小按213 次方到23 次方依次分成AllocChunk 加入到对应大小的freelist 链表数组中的链表里。到此绿色块完了,这个AllocSetAlloc 也结束了。

 

3 示例

    下面再用图例演示从TopMemoryContextAllocBlock 链表blocks 里一个block 分配一个AllockChunk 类型的变量chunk ,然后在chunk 上初始化ErrorContext 的例子。下图是只有一个AllocBlockTomMemoryContext 结构图


pg的内存管理机制一:AllocSet的内存分配_第3张图片

TopMemoryContextAllocBlock 链表blocks 里的block 中分配了一个AllockChunk 变量chunk ,就是图纸粉色的那一块。

 


pg的内存管理机制一:AllocSet的内存分配_第4张图片
 

ErrorContext 放在了新分的chunk 上。

 

 

 


pg的内存管理机制一:AllocSet的内存分配_第5张图片

 

 

 

你可能感兴趣的:(内存管理)