当前位置: 首页 > 科技观察

PHP垃圾回收机制详解

时间:2023-03-15 14:56:09 科技观察

PHP的基本GC概念PHP语言和其他语言一样,也有垃圾回收机制。那么今天我们要给大家讲解的就是关于PHP垃圾回收机制的相关问题。我希望能有所帮助。PHPstrtotime应用经验谈PHPmemory_get_usage()内存管理PHPunset全局变量使用详解PHPunset()函数销毁变量教你快速实现PHP全站权限验证一、PHP垃圾回收机制(GarbageCollector简称GC)在PHP中,当没有变量指向对象时,对象就变成了垃圾。PHP会在内存中销毁它;这是PHP的GC垃圾处理机制,防止内存溢出。当一个PHP线程结束时,当前占用的所有内存空间都会被销毁,同时销毁当前程序中的所有对象。GC进程通常随每个会话开始运行。gc的目的是在session文件过期后自动销毁删除。其次,__destruct/unset__destruct()析构函数在垃圾对象被回收时执行。unset销毁指向对象的变量,而不是对象。3、Session与PHP垃圾回收机制由于PHP的工作机制,它没有守护线程定期扫描Session信息并判断其是否无效。当发生有效请求时,PHP会使用全局变量session.gc_probability和session.gc_divisor的值来决定是否启用GC。默认情况下,session.gc_probability=1,session.gc_divisor=100表示??有1%的可能性开始GC(也就是说100个请求中只有1个gc会以100个请求中的一个开始)。PHP垃圾回收机制是扫描所有的Session信息,将当前时间减去session的修改时间,与session.gc_maxlifetime参数进行比较。如果存活时间超过gc_maxlifetime(默认24分钟),会话将被删除。但是,如果你的web服务器有多个站点,当有多个站点时,GC处理会话可能会产生意想不到的结果。原因是:GC在工作的时候不区分不同站点的session。那么这个时候怎么解决呢??修改session.save_path,或者使用session_save_path()将各个站点的session保存到专门的目录,提供GC启动率。PHP垃圾回收机制的启动速度自然会提高,系统性能也会相应下降。不推荐。代码中判断当前session的存活时间,使用session_destroy()删除。引用计数基础知识每个php变量都存在于一个名为“zval”的变量容器中。一个zval变量容器,除了包含变量的类型和值外,还包含两个字节的附加信息。第一个是"is_ref",是一个bool值,用来标识这个变量是否属于一个引用集(referenceset)。通过这个字节,PHP引擎可以区分普通变量和引用变量。由于PHP允许用户通过使用&来自定义引用,所以在zval变量容器中也有一个内部引用计数机制来优化内存使用。第二个多出来的字节是“refcount”,用来表示指向这个zval变量容器的变量(也叫symbols或symbols)的个数。当一个变量被赋予常量值时,会生成一个zval变量容器,如下例所示:在上面的例子中,新的变量是a,它是在当前范围内生成的。并生成一个类型为string,值为“newstring”的变量容器。在多出的两个字节信息中,“is_ref”默认设置为false,因为没有生成自定义引用。“refcount”设置为1,因为只有一个变量使用这个变量容器。调用xdebug检查变量内容:上面的代码会输出:a:(refcount=1,is_ref=0)='newstring'addareferencecounttovariablea上面的代码会输出:a:(refcount=2,is_ref=0)='newstring'此时引用的个数为2,因为同一个变量容器关联了变量a和变量b。不需要时,PHP不会复制已经生成的变量容器。当“refcount”变为0时,变量容器被销毁。当与变量关联的任何变量超出其范围时(例如:函数执行结束),或者对变量调用unset()函数,"refcount"会减1,下面的例子可以说明:上面的代码会输出:a:(refcount=3,is_ref=0)='newstring'a:(refcount=1,is_ref=0)='newstring'如果我们现在执行unset($a),$中包含的这种类型和值的容器将从内存中删除复合类型,当考虑像数组和对象类型这样的复合类型时,事情会变得有点复杂。与标量类型值不同,数组和对象类型变量将它们的成员或属性存储在它们自己的符号表中。这意味着以下示例将生成三个zval变量Container'life','number'=>42);xdebug_debug_zval('a');?>上面代码输出:a:(refcount=1,is_ref=0)=array('meaning'=>(refcount=1,is_ref=0)='life','number'=>(refcount=1,is_ref=0)=42)这三个zval变量容器分别是:a,meaning,number。增加和减少refcount的规则与上面提到的特殊情况相同,当将数组本身添加为数组元素时:上面代码输出的结果:a:(refcount=2,is_ref=1)=array(0=>(refcount=1,is_ref=0)='one',1=>(refcount=2,is_ref=1)=...)可以看到数组a指向的变量container和数组本身的元素a[1]的refcount为2。当对数组$a调用unset函数时,refcount$a的变为1,并发生内存泄漏以清理变量。容器问题虽然在某个作用域内不再有任何符号指向这个结构体(即变量容器),但由于数组元素“1”仍然指向数组本身,所以这个容器无法消除。因为没有其他符号指向它,用户没有办法清除这个结构,结果就会是内存泄漏。幸运的是,PHP会在请求结束时清除这个数据结构,但是在PHP清除之前,它会消耗大量的内存空间。回收循环5.3.0PHP使用了一种新的同步循环回收算法来处理上面提到的内存泄漏问题。首先,我们需要建立一些基本规则:如果一个引用计数增加了,它就会继续被使用,当然就不再是垃圾了。中等的。如果引用计数减少到零,变量容器将被清除(释放)。也就是说,只有当引用计数减少到非零值时,才会产生垃圾循环(grabagecycle)。其次,在一个垃圾循环中,通过检查引用计数是否减1,查看哪些变量容器的引用计数为零,找出哪些部分是垃圾。为了避免必须检查所有可能的垃圾循环引用计数,该算法将所有可能的根(可能的根是zval变量容器)放在根缓冲区(以紫色标记)中,这确保了每个可能的垃圾根(possiblegarbageroot)出现只有一次在缓冲区中。只有当根缓冲区已满时,才会对缓冲区内的所有不同变量容器执行垃圾回收。