SGI Memory Pool
大于 128Bytes 直接使用 malloc / free
,只管理内存,不负责构造与析构。
小于 128Bytes 使用自定义内存空间管理。
- 8、16、24、... 、128 大小的内存块指针数组统一管理
| union _Obj { union _Obj* _M_free_list_link; char _M_client_data[1]; };
|
- 每个大小内存块组织在一个大的内存空间,维护
起始地址、结束地址和对空间大小
| static char* _S_start_free; static char* _S_end_free; static size_t _S_heap_size;
|
- 组织可用内存块为一个链表,顶层管理的指针数组中的元素,指向对应内存块区域中,首个可用的内存块地址
- 申请和释放内存块,就是在改变链表的指向
当然,已经申请的内存,在内存池回收前,都不会释放。
内存池管理接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| static void* allocate(size_t __n)
static void* _S_refill(size_t __n);
static char* _S_chunk_alloc(size_t __size, int& __nobjs);
static void deallocate(void* __p, size_t __n);
template <bool threads, int inst> void* __default_alloc_template<threads, inst>::reallocate(void* __p, size_t __old_sz, size_t __new_sz);
|
另外又两个辅助函数:
地址对齐用的函数 _S_round_up
| static size_t _S_round_up(size_t __bytes) { return (((__bytes) + (size_t) _ALIGN-1) & ~((size_t) _ALIGN - 1)); }
|
内存块指针数组中找到对应 chunk 块大小的函数 _S_freelist_index
| static size_t _S_freelist_index(size_t __bytes) { return (((__bytes) + (size_t)_ALIGN-1)/(size_t)_ALIGN - 1); }
|
NGINX Memory Pool
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct ngx_pool_s { ngx_pool_data_t d; size_t max; ngx_pool_t *current; ngx_chain_t *chain; ngx_pool_large_t *large; ngx_pool_cleanup_t *cleanup; ngx_log_t *log; };
typedef struct ngx_pool_s ngx_pool_t;
typedef struct { u_char *last; u_char *end; ngx_pool_t *next; ngx_uint_t failed; } ngx_pool_data_t;
|
小块内存,通过 ngx_pool_data_t
组织为链表结构,在 last
到 end 之间分配内存使用。不足时,会新开辟一个内存块。
| struct ngx_pool_large_s { ngx_pool_large_t *next; void *alloc; };
|
大块内存,通过 ngx_pool_large_s
组织为链表,使用和释放就是包装之后的 malloc 和 free。
| typedef void (*ngx_pool_cleanup_pt)(void *data);
typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
struct ngx_pool_cleanup_s { ngx_pool_cleanup_pt handler; void *data; ngx_pool_cleanup_t *next; };
|
内存池的清理,一般在内存池销毁之前。
内存池的一般接口为:
| ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log); void ngx_destroy_pool(ngx_pool_t *pool); void ngx_reset_pool(ngx_pool_t *pool);
void *ngx_palloc(ngx_pool_t *pool, size_t size); void *ngx_pnalloc(ngx_pool_t *pool, size_t size); void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p); ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
|
小块内存池的申请,需要手动进行内存对齐,以增加内存操作的效率,因为没有使用
malloc 不会自动对齐。
| #define ngx_align_ptr(p, a) \ (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
|
这个操作的逻辑和 _S_round_up
是一致的。将指针
p
向上对齐到最接近的 a
的倍数。
实现与测试
github
link ;一个类似的简化版 NGINX 内存池实现 MemoryPool。
整体而言,自定义实现的 MemoryPool allocator 性能比 SGI Memory Pool
性能会好一些。 SGI Memory Pool 的性能和 STL 默认 allocator
性能相差无几。NGINX Memory Pool 性能会比 SGI Memory Pool 更好。但是NGINX
Memory Pool 并没有实现为 allocator 的形式。
内存管理相关
对 malloc 的进一步优化:
jemalloc
mimalloc well
document
tcmalloc
其中 jemalloc 和 mimallic 会是更优的选择。
相关学习博客推荐为:
内存分配器之jemalloc技术原理分析
JeMalloc
看了但是忘了,还是随便总结一点可能会好一些吧。