尝试在PHP扩展中写一个内部函数,结果报内存泄漏,找了半天也没找到原因
Try to write an internal function in the PHP extension, the results reported memory leak, looking for a long time did not find the reason
最近看了一本关于PHP扩展的书,准备写一个函数,函数原型如下:
array_groupBy(string $key, array $input, $forget = false):array
这个函数的作用是按照分组的值对应的$key
对$input
进行分组,$forget
表示分组后的数组是否需要delete$key
,$clourse
是可调用类型,如果存在,$key
对应的值会传给闭包函数里面,闭包函数returns新建字符串作为新数组的键,像这样:
并输出:
和源代码
PHP_FUNCTION(array_groupBy){
zend_string *key;
zval *input, *val, *key_zval;
zval group_zval, copy, retval, copy_key_zval;
zend_bool forget = 0, have_callback = 0;
HashTable *ht;
zend_fcall_info fcall_info = empty_fcall_info;
zend_fcall_info_cache fcall_info_cache = empty_fcall_info_cache;
int ret;
ZEND_PARSE_PARAMETERS_START(2, 4)
Z_PARAM_STR(key)
Z_PARAM_ARRAY(input)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(forget)
Z_PARAM_FUNC(fcall_info, fcall_info_cache)
ZEND_PARSE_PARAMETERS_END();
if(ZEND_NUM_ARGS() > 3){
have_callback = 1;
}
ht = (HashTable *)emalloc(sizeof(HashTable));
zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
ZEND_HASH_FOREACH_VAL(Z_ARR_P(input), val){
ZVAL_COPY(©, val);
key_zval = zend_symtable_find(Z_ARR_P(val), key);
if(have_callback){
ZVAL_COPY(©_key_zval, key_zval);
fcall_info.retval = &retval;
fcall_info.params = ©_key_zval;
fcall_info.no_separation = 0;
fcall_info.param_count = 1;
ret = zend_call_function(&fcall_info, &fcall_info_cache);
zval_ptr_dtor(©_key_zval);
if(ret != SUCCESS || Z_TYPE(retval) == IS_UNDEF){
zend_array_destroy(ht);
RETURN_NULL();
}
ZVAL_STR(©_key_zval, Z_STR(retval));
}else{
ZVAL_STR(©_key_zval, zend_string_dup(Z_STR_P(key_zval), 0));
}
convert_to_string(©_key_zval);
//GC_REFCOUNT(Z_STR(copy_key_zval)--;
if(zend_hash_exists(ht, Z_STR(copy_key_zval))){
group_zval = *zend_hash_find(ht, Z_STR(copy_key_zval));
}else{
array_init(&group_zval);
zend_hash_add_new(ht, Z_STR(copy_key_zval), &group_zval);
}
if(forget){
SEPARATE_ARRAY(©);
zend_symtable_del(Z_ARR(copy), key);
}
add_next_index_zval(&group_zval, ©);
}ZEND_HASH_FOREACH_END();
RETURN_ARR(ht);
}
结果正确,但报告"total 3 memory leak detected",当我打开GC_REFCOUNT(Z_STR(copy_key_zval))--
时,报告"total 1 memory leak detected"。
因为我不知道怎么调试上面的代码,导致我找了半天也找不到原因,有大佬帮帮我吗?
php_version
PHP 7.2.0-dev (cli) (built: Mar 31 2017 10:47:40) ( NTS DEBUG )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0-dev, Copyright (c) 1998-2017 Zend Technologies
您没有在将 copy_key_zval
中的字符串添加到数组后释放它。当它最初被创建时,它的引用计数为 1,当它被添加到数组中时,它的引用计数为 2; PHP 假定您的函数挂在它上面,直到您另有说明。使用后需要zval_ptr_dtor()
释放内容
同样,您不会在 copy
中分离数组后释放它。
最近看了一本关于PHP扩展的书,准备写一个函数,函数原型如下:
array_groupBy(string $key, array $input, $forget = false):array
这个函数的作用是按照分组的值对应的$key
对$input
进行分组,$forget
表示分组后的数组是否需要delete$key
,$clourse
是可调用类型,如果存在,$key
对应的值会传给闭包函数里面,闭包函数returns新建字符串作为新数组的键,像这样:
并输出:
和源代码
PHP_FUNCTION(array_groupBy){
zend_string *key;
zval *input, *val, *key_zval;
zval group_zval, copy, retval, copy_key_zval;
zend_bool forget = 0, have_callback = 0;
HashTable *ht;
zend_fcall_info fcall_info = empty_fcall_info;
zend_fcall_info_cache fcall_info_cache = empty_fcall_info_cache;
int ret;
ZEND_PARSE_PARAMETERS_START(2, 4)
Z_PARAM_STR(key)
Z_PARAM_ARRAY(input)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(forget)
Z_PARAM_FUNC(fcall_info, fcall_info_cache)
ZEND_PARSE_PARAMETERS_END();
if(ZEND_NUM_ARGS() > 3){
have_callback = 1;
}
ht = (HashTable *)emalloc(sizeof(HashTable));
zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
ZEND_HASH_FOREACH_VAL(Z_ARR_P(input), val){
ZVAL_COPY(©, val);
key_zval = zend_symtable_find(Z_ARR_P(val), key);
if(have_callback){
ZVAL_COPY(©_key_zval, key_zval);
fcall_info.retval = &retval;
fcall_info.params = ©_key_zval;
fcall_info.no_separation = 0;
fcall_info.param_count = 1;
ret = zend_call_function(&fcall_info, &fcall_info_cache);
zval_ptr_dtor(©_key_zval);
if(ret != SUCCESS || Z_TYPE(retval) == IS_UNDEF){
zend_array_destroy(ht);
RETURN_NULL();
}
ZVAL_STR(©_key_zval, Z_STR(retval));
}else{
ZVAL_STR(©_key_zval, zend_string_dup(Z_STR_P(key_zval), 0));
}
convert_to_string(©_key_zval);
//GC_REFCOUNT(Z_STR(copy_key_zval)--;
if(zend_hash_exists(ht, Z_STR(copy_key_zval))){
group_zval = *zend_hash_find(ht, Z_STR(copy_key_zval));
}else{
array_init(&group_zval);
zend_hash_add_new(ht, Z_STR(copy_key_zval), &group_zval);
}
if(forget){
SEPARATE_ARRAY(©);
zend_symtable_del(Z_ARR(copy), key);
}
add_next_index_zval(&group_zval, ©);
}ZEND_HASH_FOREACH_END();
RETURN_ARR(ht);
}
结果正确,但报告"total 3 memory leak detected",当我打开GC_REFCOUNT(Z_STR(copy_key_zval))--
时,报告"total 1 memory leak detected"。
因为我不知道怎么调试上面的代码,导致我找了半天也找不到原因,有大佬帮帮我吗?
php_version
PHP 7.2.0-dev (cli) (built: Mar 31 2017 10:47:40) ( NTS DEBUG )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.2.0-dev, Copyright (c) 1998-2017 Zend Technologies
您没有在将 copy_key_zval
中的字符串添加到数组后释放它。当它最初被创建时,它的引用计数为 1,当它被添加到数组中时,它的引用计数为 2; PHP 假定您的函数挂在它上面,直到您另有说明。使用后需要zval_ptr_dtor()
释放内容
同样,您不会在 copy
中分离数组后释放它。