PHP 内存管理 写时复制 垃圾回收
Posted 略略略。。。。
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP 内存管理 写时复制 垃圾回收相关的知识,希望对你有一定的参考价值。
php中的变量是不需要手动释放的,内核帮我们实现了变量的内存管理,包括内存的分配和回收
变量深拷贝带来的问题就是效率和内存浪费严重。
解决深拷贝:1、引用计数 2、写时复制
PHP变量的内存管理就是基于这两点实现的
当变量赋值、引用的时候不是进行深拷贝,而是多个变量共用一个value,引用计数来记录这个变量被引用过多少次,当其中的一个变量发生变化时将无法与其他的变量共用
value时,这个时候就需要进行深拷贝进行分离value,这就是写时复制。
引用计数:
用来记录当前有多少个zval指向同一个zend_value,当有新的zval指向这个value时,计数器+1,当zval销毁时,计数书-1,当计数器为0,value就释放来。
PHP7的引用计数保存在了zend_value中,成员gc用来保存引用计数的。PHP中的局部变量zavl分配在zend_execute_data结构上,也就是我们调试的execute_ex函数中的
execute_data变量,它是运行期间最重要,最关键的一个结构,用于局部变量的分配、保存执行位置、调用上下文切换等。
写时复制:
它只有在有必要的时候即发生写的时候才进行深拷贝,可以很好的提高效率,例如Linux操作系统中fork子进程时并不会立即复制父进程的地址空间,而是让父子进程共享一个内存空间,只有在需要写入的时候才会复制地址空间,从而使各个进程拥有各自独立的地址空间,也就是说资源的复制是在需要写入的时候才会进行,在此之前,以只读方式共享。也并不是所有的类型都可以进行复制,对象资源就无法进行复制。
自动GC回收:
在zval断开value的执行是如果发现refounct=0则会直接释放value,这就是变量的回收时机,发生断开的两种常用情况为修改变量与函数返回时,修改变量是会断开value的指向,函数返回时会释放所有的变量。使用unset()函数也可以主动销毁一个变量
垃圾回收:
通过引用计数实现了变量的自动GC机制,但是有一种情况是这个机制无法解决的,从而因变量无法回收导致内存始终得不到释放,造成内存泄漏。这种情况就是循环引用,循环引用就是引用了自身导致无法释放,比如数组中元素引用了这个数组。因为这种因为循环引用而导致无法释放的变量称之为垃圾,PHP引用了另一种机制来对这些垃圾进行回收,也就是垃圾回收器:
这里要明确,如果一个变量value的refcount减少到0,value释放,不属于垃圾。如果一个变量的refcount减少之后大于0,那这可能是垃圾,垃圾回收器会把这种变量收集起来,垃圾回收器会把这种垃圾保存到一个buffer缓存区,等达到一定数量后就会启动垃圾鉴定回收程序,回收算法原理其实很简单,既然垃圾回收是因为引用自身引起的啊,那我就把value的refcount减1,如果返回是0就说明是垃圾,否则再把减1恢复,说明是正常变量。
以上是关于PHP 内存管理 写时复制 垃圾回收的主要内容,如果未能解决你的问题,请参考以下文章