|
| 1 | +# ZendMM |
| 2 | + |
| 3 | +1, php内存管理内置函数 |
| 4 | + |
| 5 | + void *emalloc(size_t size) 分配 size 字节的内存。 |
| 6 | + void *ecalloc(size_t nmemb, size_t size) 给 nmemb 元素分配 size 字节的缓冲区并初始化为零。 |
| 7 | + void *erealloc(void *ptr, size_t size) 修改使用 emalloc 分配的缓冲区 ptr 的大小为 size 字节。 |
| 8 | + void efree(void *ptr) 释放 ptr 指向的缓冲区。缓冲区必须是由 emalloc 分配的。 |
| 9 | + void *safe_emalloc(size_t nmemb, size_t size, size_t offset) |
| 10 | + char *estrdup(const char *s) 分配一个可存放 NULL 结尾的字符串 s 的缓冲区,并将 s复制到缓冲区内。 |
| 11 | + char *estrndup(const char *s, unsigned int length) 类似于 estrdup,但 NULL 结尾的字符串长度是已知的。 |
| 12 | + |
| 13 | +2,由emalloc分配的内存都是在zend_mm_heap上 |
| 14 | + |
| 15 | + //zend_mm_mem_handlers |
| 16 | + typedef struct _zend_mm_mem_handlers { |
| 17 | + const char *name; |
| 18 | + zend_mm_storage* (*init)(void *params); |
| 19 | + void (*dtor)(zend_mm_storage *storage); |
| 20 | + void (*compact)(zend_mm_storage *storage); |
| 21 | + zend_mm_segment* (*_alloc)(zend_mm_storage *storage, size_t size); |
| 22 | + zend_mm_segment* (*_realloc)(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size); |
| 23 | + void (*_free)(zend_mm_storage *storage, zend_mm_segment *ptr); |
| 24 | + } zend_mm_mem_handlers; |
| 25 | + |
| 26 | + //zend_mm_segment |
| 27 | + typedef struct _zend_mm_segment { |
| 28 | + size_t size; |
| 29 | + struct _zend_mm_segment *next_segment; |
| 30 | + } zend_mm_segment; |
| 31 | + |
| 32 | + //zend_mm_storage结构 |
| 33 | + struct _zend_mm_storage { |
| 34 | + const zend_mm_mem_handlers *handlers;//zend_mm_storage方法 (ZEND_MM_MEM_MALLOC_DSC) |
| 35 | + void *data; |
| 36 | + }; |
| 37 | + |
| 38 | + //zend_mm_heap结构 |
| 39 | + struct _zend_mm_heap { |
| 40 | + int use_zend_alloc; |
| 41 | + void *(*_malloc)(size_t); |
| 42 | + void (*_free)(void*); |
| 43 | + void *(*_realloc)(void*, size_t); |
| 44 | + size_t free_bitmap; |
| 45 | + size_t large_free_bitmap; |
| 46 | + size_t block_size; |
| 47 | + size_t compact_size; |
| 48 | + zend_mm_segment *segments_list; |
| 49 | + zend_mm_storage *storage; |
| 50 | + size_t real_size; |
| 51 | + size_t real_peak; |
| 52 | + size_t limit; |
| 53 | + size_t size; |
| 54 | + size_t peak; |
| 55 | + size_t reserve_size; |
| 56 | + void *reserve; |
| 57 | + int overflow; |
| 58 | + int internal; |
| 59 | + #if ZEND_MM_CACHE |
| 60 | + unsigned int cached; |
| 61 | + zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS]; |
| 62 | + #endif |
| 63 | + zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2]; |
| 64 | + zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS]; |
| 65 | + zend_mm_free_block *rest_buckets[2]; |
| 66 | + int rest_count; |
| 67 | + #if ZEND_MM_CACHE_STAT |
| 68 | + struct { |
| 69 | + int count; |
| 70 | + int max_count; |
| 71 | + int hit; |
| 72 | + int miss; |
| 73 | + } cache_stat[ZEND_MM_NUM_BUCKETS+1]; |
| 74 | + #endif |
| 75 | + }; |
| 76 | + |
| 77 | + //zend_alloc_globals结构 |
| 78 | + typedef struct _zend_alloc_globals { |
| 79 | + zend_mm_heap *mm_heap; |
| 80 | + } |
| 81 | + |
| 82 | + //AG宏定义 |
| 83 | + # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v) |
| 84 | + |
| 85 | + //emalloc函数原型 |
| 86 | + ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) |
| 87 | + { |
| 88 | + TSRMLS_FETCH(); |
| 89 | + |
| 90 | + if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { |
| 91 | + return AG(mm_heap)->_malloc(size); |
| 92 | + } |
| 93 | + return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); |
| 94 | + } |
| 95 | + |
| 96 | +3,ZendMM环境变量 |
| 97 | + |
| 98 | +USE_ZEND_ALLOC 是否使用 ZendMM 进行内存管理。 |
| 99 | +ZEND_MM_MEM_TYPE 指定内存分配的方案,默认 malloc |
| 100 | +ZEND_MM_COMPACT 指定压缩边界值 |
| 101 | + |
| 102 | +//默认ZEND_MM_MEM_TYPE初始化 |
| 103 | + |
| 104 | + # 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} |
| 105 | + |
| 106 | + # 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} |
| 107 | + |
| 108 | + # 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} |
| 109 | + |
| 110 | + # 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} |
| 111 | + |
| 112 | +4,ZendMM 流程 |
| 113 | + |
| 114 | + ->SAPI |
| 115 | + ->php_module_startup (main.c 2065) |
| 116 | + ->zend_startup() //zend引擎启动 |
| 117 | + ->start_memory_manager(TSRMLS_C) //开始内存管理 |
| 118 | + ->ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor) //初始化AG |
| 119 | + |
| 120 | + ->alloc_globals_ctor(&alloc_globals) //申请内存 |
| 121 | + |
| 122 | + //分配内存,读取环境变量USE_ZEND_ALLOC,如果USE_ZEND_ALLOC==0 则禁用 ZendMMApi(emalloc/efree/...) |
| 123 | + //初始化mm_heap的代码(USE_ZEND_ALLOC != 0) |
| 124 | + alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap)); |
| 125 | + memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap)); |
| 126 | + alloc_globals->mm_heap->use_zend_alloc = 0; |
| 127 | + alloc_globals->mm_heap->_malloc = malloc; |
| 128 | + alloc_globals->mm_heap->_free = free; |
| 129 | + alloc_globals->mm_heap->_realloc = realloc; |
| 130 | + |
| 131 | + //初始化mm_heap的代码(USE_ZEND_ALLOC != 0), 则启用 ZendMMApi(emalloc/efree/...) |
| 132 | + alloc_globals->mm_heap = zend_mm_startup(); |
| 133 | + |
| 134 | + ->zend_mm_startup() //读取内存分配方案(默认malloc) |
| 135 | + ->zend_mm_startup_ex() //实例化zend_mm_heap分配内存 (heap = malloc(sizeof(struct _zend_mm_heap));) |
| 136 | + |
| 137 | + ->emalloc() //申请内存, |
| 138 | + //zend_mm_heap->use_zend_alloc==0 调用 mm_heap->_malloc方法初始化分配内存 |
| 139 | + //zend_mm_heap->use_zend_alloc!=0 调用 _zend_mm_alloc_int |
| 140 | + ->_zend_mm_alloc_int() |
| 141 | + ->ZEND_MM_STORAGE_ALLOC(segment_size) // |
| 142 | + -> heap->storage->handlers->_alloc |
| 143 | + |
| 144 | + //ZEND_MM_MEM_WIN32_DSC |
| 145 | + ->zend_mm_mem_win32_alloc() |
| 146 | + ->HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size)//最终把内存分配到了heap->storage->data |
| 147 | + |
| 148 | + //ZEND_MM_MEM_MALLOC_DSC |
| 149 | + ->zend_mm_mem_malloc_alloc() |
| 150 | + ->return (zend_mm_segment*)malloc(size) //最终把内存分配到了 heap->segments_list |
| 151 | + |
| 152 | + //ZEND_MM_MEM_MMAP_ZERO_DSC |
| 153 | + ->zend_mm_mem_mmap_zero_alloc() |
| 154 | + ->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0) //通过mmap把内存影射到heap->storage |
| 155 | + |
| 156 | + //ZEND_MM_MEM_MMAP_ANON_DSC |
| 157 | + ->zend_mm_mem_mmap_anon_alloc |
| 158 | + ->(zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0) |
| 159 | + //最终把内存分配到了 heap->segments_list |
| 160 | + |
| 161 | + ->alloc_globals_dtor() //释放内存 |
| 162 | + ->shutdown_memory_manager (main.c 2410) //结束内存管理 |
| 163 | + ->zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC) //最终调用释放内存的方法 |
| 164 | + |
| 165 | +5,总结 |
| 166 | + |
| 167 | + a) ZEND_MM_MEM_WIN32_DSC|ZEND_MM_MEM_MMAP_ZERO_DSC 内存保存到了 heap->storage |
| 168 | + ZEND_MM_MEM_MMAP_ANON_DSC|ZEND_MM_MEM_MALLOC_DSC 内存保存到了 heap->segments_list |
| 169 | + |
| 170 | + b) |
0 commit comments