When to free memory in a PHP extension?
Asked Answered
F

2

6

I'd like to create and return an array of arrays in a PHP extension. From what I understand, I should allocate the space for the array elements using emalloc(), but what I don't understand is when it is appropriate to free it. I have a PHP function similar to this:

PHP_FUNCTION(test)
{
    int i;
    zval **pt = emalloc(sizeof(zval*) * 10);

    array_init(return_value);

    for (i = 0; i < 10; ++i) {
        MAKE_STD_ZVAL(pt[i]);
        array_init(pt[i]);
        add_index_double(pt[i], 0, 1);
        add_index_zval(return_value, i, pt[i]);
    }
}

Where should I free the memory allocated for pt?

Feces answered 10/4, 2012 at 16:45 Comment(0)
G
6

In this case, you don't have to. When the variable that you're returning is destroyed, its memory is freed. Since you're returning an array, all the elements of the array will be destroyed by that time as well (to be more precise, their reference count is decreased when the array is deleted, only if they have no other references by that time will they be freed).

You can manually decrease the reference count of a zval by calling zval_ptr_dtor. When its reference count reaches 0, this will free its memory as well.

Technically, an array variable is backed by a HashTable. When the variable is destroyed, the hash table is destroyed as well. By this, the "destructor callback" associated with the HashTable as called as well, once with each of the hash table elements as an argument. When you call array_init, it also creates a hash table with zval_ptr_dtor as the destructor function.

Also note that you make calls to emalloc in two places here. The first is explicit, the other is via MAKE_STD_ZVAL. The first one is unnecessary, but if you use it, you should call efree before your function returns otherwise its memory leaks because it's not associated with any automatic memory management mechanism like PHP variables are.

Guerrilla answered 10/4, 2012 at 17:46 Comment(2)
I am calling array_init(pt[i]); right after MAKE_STD_ZVAL(), forgot to add it to the example. So, if I understand correctly, I shouldn't call emalloc() at all, because MAKE_STD_ZVAL() is responsible for allocating the memory, and the memory gets deallocated when its reference count arrives at zero (and that should happen when it gets out of scope in PHP, if it's only referenced once).Feces
@Radu Yes, MAKE_STD_ZVAL allocates (with emalloc) the zval as well. However, your first call to emalloc is not allocating a zval, it's allocating array of 10 zval*, which is not the same thibg. Like actual said, you can use a local variable for that, or you can abandon the array completely and do: { zval *zv; MAKE_STD_ZVAL(zv); add_index_double(zv, 0, 1); add_index_zval(return_value, i, zv); }.Guerrilla
O
1

There is no need to allocate memory using emalloc in this case, just use zval *pt[10] or reduce it to single reusable zval, MAKE_STD_ZVAL will handle all memory (de)allocation and reference counting stuff.

Otter answered 10/4, 2012 at 17:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.