Skip to content

Commit 863f825

Browse files
committed
add ZendMM
1 parent ead551e commit 863f825

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

004.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
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)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
[3,zval](./003.md)
3838

39+
[4, ZendMM](./004.md)
40+
3941
##### 参考
4042

4143
[https://github.com/sgolemon/phptek2013](https://github.com/sgolemon/phptek2013)

0 commit comments

Comments
 (0)