1, php内存管理内置函数
void *emalloc(size_t size) 分配 size 字节的内存。
void *ecalloc(size_t nmemb, size_t size) 给 nmemb 元素分配 size 字节的缓冲区并初始化为零。
void *erealloc(void *ptr, size_t size) 修改使用 emalloc 分配的缓冲区 ptr 的大小为 size 字节。
void efree(void *ptr) 释放 ptr 指向的缓冲区。缓冲区必须是由 emalloc 分配的。
void *safe_emalloc(size_t nmemb, size_t size, size_t offset)
char *estrdup(const char *s) 分配一个可存放 NULL 结尾的字符串 s 的缓冲区,并将 s复制到缓冲区内。
char *estrndup(const char *s, unsigned int length) 类似于 estrdup,但 NULL 结尾的字符串长度是已知的。
2,由emalloc分配的内存都是在zend_mm_heap上
//zend_mm_mem_handlers
typedef struct _zend_mm_mem_handlers {
const char *name;
zend_mm_storage* (*init)(void *params);
void (*dtor)(zend_mm_storage *storage);
void (*compact)(zend_mm_storage *storage);
zend_mm_segment* (*_alloc)(zend_mm_storage *storage, size_t size);
zend_mm_segment* (*_realloc)(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size);
void (*_free)(zend_mm_storage *storage, zend_mm_segment *ptr);
} zend_mm_mem_handlers;
//zend_mm_segment
typedef struct _zend_mm_segment {
size_t size;
struct _zend_mm_segment *next_segment;
} zend_mm_segment;
//zend_mm_storage结构
struct _zend_mm_storage {
const zend_mm_mem_handlers *handlers;//zend_mm_storage方法 (ZEND_MM_MEM_MALLOC_DSC)
void *data;
};
//zend_mm_heap结构
struct _zend_mm_heap {
int use_zend_alloc;
void *(*_malloc)(size_t);
void (*_free)(void*);
void *(*_realloc)(void*, size_t);
size_t free_bitmap;
size_t large_free_bitmap;
size_t block_size;
size_t compact_size;
zend_mm_segment *segments_list;
zend_mm_storage *storage;
size_t real_size;
size_t real_peak;
size_t limit;
size_t size;
size_t peak;
size_t reserve_size;
void *reserve;
int overflow;
int internal;
#if ZEND_MM_CACHE
unsigned int cached;
zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
#endif
zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
zend_mm_free_block *rest_buckets[2];
int rest_count;
#if ZEND_MM_CACHE_STAT
struct {
int count;
int max_count;
int hit;
int miss;
} cache_stat[ZEND_MM_NUM_BUCKETS+1];
#endif
};
//zend_alloc_globals结构
typedef struct _zend_alloc_globals {
zend_mm_heap *mm_heap;
}
//AG宏定义
# define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
//emalloc函数原型
ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
TSRMLS_FETCH();
if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
return AG(mm_heap)->_malloc(size);
}
return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
3,ZendMM环境变量
USE_ZEND_ALLOC 是否使用 ZendMM 进行内存管理。 ZEND_MM_MEM_TYPE 指定内存分配的方案,默认 malloc ZEND_MM_COMPACT 指定压缩边界值
//默认ZEND_MM_MEM_TYPE初始化
# define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}
# define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
# define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
# define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
4,ZendMM 流程
->SAPI
->php_module_startup (main.c 2065)
->zend_startup() //zend引擎启动
->start_memory_manager(TSRMLS_C) //开始内存管理
->ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor) //初始化AG
->alloc_globals_ctor(&alloc_globals) //申请内存
//分配内存,读取环境变量USE_ZEND_ALLOC,如果USE_ZEND_ALLOC==0 则禁用 ZendMMApi(emalloc/efree/...)
//初始化mm_heap的代码(USE_ZEND_ALLOC != 0)
alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap));
memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap));
alloc_globals->mm_heap->use_zend_alloc = 0;
alloc_globals->mm_heap->_malloc = malloc;
alloc_globals->mm_heap->_free = free;
alloc_globals->mm_heap->_realloc = realloc;
//初始化mm_heap的代码(USE_ZEND_ALLOC != 0), 则启用 ZendMMApi(emalloc/efree/...)
alloc_globals->mm_heap = zend_mm_startup();
->zend_mm_startup() //读取内存分配方案(默认malloc)
->zend_mm_startup_ex() //实例化zend_mm_heap分配内存 (heap = malloc(sizeof(struct _zend_mm_heap));)
->emalloc() //申请内存,
//zend_mm_heap->use_zend_alloc==0 调用 mm_heap->_malloc方法初始化分配内存
//zend_mm_heap->use_zend_alloc!=0 调用 _zend_mm_alloc_int
->_zend_mm_alloc_int()
->ZEND_MM_STORAGE_ALLOC(segment_size) //
-> heap->storage->handlers->_alloc
//ZEND_MM_MEM_WIN32_DSC
->zend_mm_mem_win32_alloc()
->HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size)//最终把内存分配到了heap->storage->data
//ZEND_MM_MEM_MALLOC_DSC
->zend_mm_mem_malloc_alloc()
->return (zend_mm_segment*)malloc(size) //最终把内存分配到了 heap->segments_list
//ZEND_MM_MEM_MMAP_ZERO_DSC
->zend_mm_mem_mmap_zero_alloc()
->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0) //通过mmap把内存影射到heap->storage
//ZEND_MM_MEM_MMAP_ANON_DSC
->zend_mm_mem_mmap_anon_alloc
->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)
//最终把内存分配到了 heap->segments_list
->alloc_globals_dtor() //释放内存
->shutdown_memory_manager (main.c 2410) //结束内存管理
->zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC) //最终调用释放内存的方法
5,总结
a) ZEND_MM_MEM_WIN32_DSC|ZEND_MM_MEM_MMAP_ZERO_DSC 内存保存到了 heap->storage ZEND_MM_MEM_MMAP_ANON_DSC|ZEND_MM_MEM_MALLOC_DSC 内存保存到了 heap->segments_list
b)