PHP内核pemalloc的persistent硬编码为1,我们该如何去进行释放
举个例子,在PHP内核初始化interned string的时候,PHP内核使用的是pemalloc,并且persistent设置为了1:
1 2 3 4 5 6 7 8 9 10
| ZEND_API void zend_interned_strings_init(void) { zend_known_strings = pemalloc(sizeof(zend_string*) * ((sizeof(known_strings) / sizeof(known_strings[0]) - 1)), 1); for (i = 0; i < (sizeof(known_strings) / sizeof(known_strings[0])) - 1; i++) { str = zend_string_init(known_strings[i], strlen(known_strings[i]), 1); zend_known_strings[i] = zend_new_interned_string_permanent(str); } }
|
我们看到zend_known_strings这个地方是通过pemalloc来分配内存的,并且persistent设置为1了。但是释放的时候,我们发现用的是free,而不是pefree:
1 2 3 4 5 6 7
| ZEND_API void zend_interned_strings_dtor(void) { zend_hash_destroy(&interned_strings_permanent);
free(zend_known_strings); zend_known_strings = NULL; }
|
实际上,当persistent为1的时候,pemalloc就是malloc。所以,这里可以用free来进行释放。但是,当时我觉得,为了对应pemalloc,释放的时候用pefree会更好一点。于是我改成了pefree(zend_known_strings, 1),但是,nikic给我的解释如下:
1 2 3
| 通常,只有在动态传递persistent时才使用pefree()。
我们有时使用pemalloc(x, 1)和硬编码的persistent=1,但这是有原因的:pemalloc(x, 1)是一个“可靠的分配器”,永远不会返回NULL。因此,它与malloc(x)不同。
|
我们可以看一下pemalloc会做什么:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #define pemalloc(size, persistent) ((persistent)?__zend_malloc(size):emalloc(size))
ZEND_API void * __zend_malloc(size_t len) { void *tmp = malloc(len); if (EXPECTED(tmp || !len)) { return tmp; } zend_out_of_memory(); }
static ZEND_COLD ZEND_NORETURN void zend_out_of_memory(void) { fprintf(stderr, "Out of memory\n"); exit(1); }
|
所以,当pemalloc的persistent为1的时候,实际上还是调用的malloc,但是会去判断是否成功的分配到了内存,如果没有分配到内存,直接退出进程。所以,我们可以认为,pemalloc的返回值一定不是NULL,如果是NULL,直接退出进程。
所以,我们可以得出一个结论,如果我们确定了内存一定是通过malloc分配的,那么,我们可以直接使用free来释放内存(用不用pefree都无所谓了);但是如果不能够确定是不是malloc来分配的,那么,我们应该使用pefree来释放内存(此时persistent应该是一个变量,而不是硬编码)