PHP内存管理
2021-08-27 16:24:58 小德 PHP 访问次数 183

一、变量自动GC

1、在函数中定义变量时,分配一块内存用于保存zval以及对应的value结构,在函数返回时再将内存释放,如果在函数执行期间该变量作为参数调用了其他函数或者赋值给了其他变量,则把变量赋值赋值一份,变量之间相互独立不会冲突。这种方法会带来深拷贝的问题,内存浪费,基于此,当变量赋值时、传递时不进行深拷贝,而是多个变量公用一个value,引用计数来记录value有多少个变量在使用,当某个变量改变时无法继续与其他变量公用value,这个时候进行深拷贝分离value,这就是写时复制。

二、引用计数

引用计数用来记录当前有多少个zval指向同一个zend_value,当新的zval指向value时  计数器+1,当zval销魂时计数器-1 ,当引用计数为0时可以对value进行释放了。

并不是所有的类型都会用到引用计数,没有具体value结构的类型是不会用到的。比如整型,浮点型,bool型,它们的值都是保存在zval中,不会公用value,而是深拷贝。

三、写时复制

发生写的时候才会进行深拷贝,比如linux中fork子进程并不会立即复制父进程的地址空间,只有写入时才会复制空间。写之前都是只读方式共享。

并不是所有的类型的value都可以进行复制,比如对象,资源就无法复制,也就是无法进行分离,只有string  和array支持value的分离。

四、回收时机

在GC中,zval断块value时发现引用计数为0,则释放value,这就是变量的回收,此外还可以通过unset()主动销魂一个变量。

五、垃圾回收

$a = array(1);

$a[] = &$a;

unset($a); //变量$a的类型为引用,refcount=2,一个来自$a 一个来自$a[1];unset之后只减少了1 ,这种因为循环引用带来的无法释放的变量成为垃圾;如果变量value释放之后refcount==0 次变量可以释放不能称谓垃圾;如果变量释放后refcount大于1则可能成为一个垃圾,目前垃圾只会出现在array和object这两种类型中。

垃圾回收把可能垃圾保存到一个buffer中,每次refcount减小时都会试图收集垃圾。

六、回收算法

垃圾回收器中的垃圾达到一定数量,进行垃圾鉴定,回收程序。

对value的所有成员减1遍引用计数,结果发现refcount=0,则表明其来自自身成员的引用,开启回收程序。

七、内存池

ZendMM用于替换glibc的malloc free  以解决频繁分配释放内存的问题。有效控制内存碎片的产生。