PHP底层
PHP垃圾回收机制
#### 什么是垃圾 如果一个zval 没有任何变量引用它,那它就是垃圾 #### 为啥要清理垃圾? 有人说php线程结束时会销毁所有变量,关闭所有句柄资源,不是自动的嘛,为啥要清理? 如果php 短时间内处理多个大文件时(如1G的电影),处理完不回收继续处理下一个,会造成内存溢出。 如果php 是个守护进程或者长时间运行的脚本,不回收垃圾,慢慢积累会造成内存溢出。 #### 如何清理垃圾 - 第一步 找垃圾 >通过 get_defined_vars 查看所有已定义变量 - 底层代码 zend_globals.h 定义了存储所有变量的两个哈希表 ```php struct _zend_executor_globals { ... HashTable *active_symbol_table; //局部变量符号表 HashTable symbol_table; //全局变量符号表 ... } ``` - 找到所有已定义的变量后,寻找哪些变量引用数为0 ```php struct _zval_struct{ ... zend_uint refcount__gc; zend_uchar is_ref__gc; ... } ``` - 第二步 清理垃圾 如上面将 refcount\__gc 为0的变量清除,这个思路是 PHP5.2版本之前的做法了。PHP5.3后用 引用计数系统中同步周期回收 算法来清除。 #### 引用计数系统中同步周期回收算法 在php中,每个变量存在一个叫“zval”的变量容器中。一个zval变量容器,除了包含变量的类型和值,还包括另外两个字节的额外信息。第一个是"is_ref"。第二个是"refcount"。 is_ref是一个布尔类型的值,用来标示这个变量是否属于引用集合。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过"&"来使用自定义的引用,所以zval中还有一个内部引用计数机制,来进行优化内存。 refcount用来表示这个zval变量容器的变量的个数。所有符号存在一个符号表当中,每个符号都有作用域。 通俗的讲:refcount就是多少个变量是一样的用了相同的值,那么refcount就是这个值。is_ref就是当有变量用了&的形式进行赋值,那么is_ref的值就会增加 引用计数的基本思想是如果一个引用计数增加那么将继续被使用,当然就不再是垃圾。如果引用计数减少到零,所在变量容器将被清除。那么也就是说只有在引用计数减少到非零值时,才会产生垃圾周期。在一个垃圾周期中通过检查引用计数是否减1,并且检查哪些变量容器的引用次数为零,来发现哪些是垃圾。 在php中垃圾回收机制默认是打开的,在你的php.ini中可以手动设置,通过zend.enable_gc这个属性进行开启或关闭垃圾回收机制。当开启了垃圾回收机制后,每当根缓存区存满时,就会执行上面描述的循环查找算法。根缓存区具有固定的大小,当然你可以通过修改php源码文件Zend/zend_gc.c中常量GC_ROOT_BUFFER_MAX_ENTRIES来修改根缓存区的大小(注意修改后需要重新编译php)。当关闭垃圾回收机制后,这个循环查找算法将不会执行,然而可能根会一直存在于根缓冲区中,不管在配置中是否激活了垃圾回收机制。 #### 何时清除 疑似垃圾会存放到一个区域(垃圾站),只有垃圾站满了才会立刻清除。 注意前提是开启垃圾回收。 开启垃圾回收两种方式 - php.ini 下的 zend.enable_gc = On 默认开启 - 通过 gc_enable() 和 gc_disable() 来打开或关闭垃圾回收 可以直接使用 gc_collect_cycles() 函数强制执行周期回收 最后说了那么多,其实只需要了解其中的原理,整个过程不需要PHP开发人员参与,只需要调用 gc_enable() 或 gc_collect_cycles() 即可实现自动回收。 #### 关于垃圾回收的小知识点 - unset():unset()只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数减1,内存是否回收主要还是看refcount是否到0了。 - null:将null赋值给一个变量是直接将该变量指向的数据结构置空,同时将其引用计数归0。 - 脚本执行结束:该脚本中所有内存都会被释放,无论是否有引用
顶部
收展
底部
[TOC]
目录
PHP核心架构
PHP执行流程
PHP运行模式
PHP生命周期
PHP Zend引擎介绍
PHP垃圾回收机制
相关推荐
PHP面向对象
PHP应用
PHP工具类
PHP编程经验
PHP框架