php扩展内存管理与引用计数
在PHP内核中,大多数情况下都不应该直接使用C语言中自带着malloc、free、strdup、realloc、calloc等操作内存的函数,而应使用内核提供的操作内存的函数,这样可以由内核整体统一的来管理内存。
对于C语言来说,使用malloc()、calloc()、realloc()等动态分配的内存,如果没有指针指向他,就无法进行任何操作,这段内存会一直被程序占用,知道程序运行结束由操作系统回收。
就php代码本身来说,变量是请求感知的,当一个请求结束时,它能够执行与OS在一个进程终止时相同的行为。也就是说,它会隐式地释放所有的为该请求所占用的内存。
C语言原生函数 | PHP内核封装后的函数 |
void malloc(size_t count); | void emalloc(size_t count);void pemalloc(size_t count, char persistent); |
void calloc(size_t count); | void ecalloc(size_t count);void pecalloc(size_t count, char persistent); |
void realloc(void ptr, size_t count); | void erealloc(void ptr, size_t count);void perealloc(void ptr, size_t count, char persistent); |
void strdup(void ptr); | void estrdup(void ptr);void pestrdup(void ptr, char persistent); |
void free(void ptr); | void efree(void ptr);void pefree(void *ptr, char persistent); |
对于zval类型的数据,使用的是”引用计数“的技术,至少会有4个成员
1.变量类型 2. 变量值 3. is_ref 代表是否有地址引用 4. refcount 指向该值的变量数量
初始化时,is_ref 为false表示未引用,refcount为1
当一个变量被引用,则zval容器中refcount会减1变为1,变量c指向a,所以refcount会加1变为2,is_ref变为true
垃圾处理时,
如果发现一个zval容器中的refcount在增加,说明不是垃圾
如果发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收
如果发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象
当缓冲区达到临界值,PHP会自动调用一个方法取遍历每一个值,如果发现是垃圾就清理
但是在php扩展中,引用次数需要手动计数,而不会自动计数,这就意味着需要手工管理内存
一般会使用 zval_ptr_dtor(zval *) 减少引用次数
增加则使用 Z_ADDREF_P(zval *) 增加引用次数
一般有几种情况,需要增加引用次数
(1)变量赋值: 变量赋值是最常见的情况,一个用到引用计数的变量类型在初始赋值时其refcount=1,如果后面把此变量又赋值给了其他变量那么就会相应的增加其引用计数
(2)数组操作: 如果把一个变量插入数组中那么就需要增加这个变量的引用计数,如果要删除一个数组元素则要相应的减少其引用
(3)函数调用: 传参实际可以当做普通的变量赋值,将调用空间的变量赋值给被调函数空间的变量,函数返回时会销毁函数空间的变量,这时又会减掉传参的引用,这两个过程由内核完成,不需要扩展自己处理
(4)成员属性: 当把一个变量赋值给对象的成员属性时需要增加引用计数
文章作者: 朱丰华
文章链接: https://smart.52dixiaowo.com/blog/post-428.html
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。