3,配置的销毁
在sapi生命周期结束的时候,比如apache关闭,cli程序执行完毕等等。一旦进入到这个阶段,之前所说的configuration_hash,EG(ini_directives)等都需要被销毁,其用到的内存空间需要被释放。
1,php会依次结束所有的模块,在每个模块的PHP_MSHUTDOWN_FUNCTION中调用UNREGISTER_INI_ENTRIES。UNREGISTER_INI_ENTRIES和REGISTER_INI_ENTRIES对应,但是UNREGISTER_INI_ENTRIES并不负责模块全局空间的释放,XXX_globals这块内存放在静态数据区上,无需人为回收。
UNREGISTER_INI_ENTRIES主要做的事情,是将某个模块的ini_entry配置从EG(ini_directives)表中删除。删除之后,ini_entry本身的空间会被回收,但是ini_entry->value不一定会被回收。
当所有模块的PHP_MSHUTDOWN_FUNCTION都调用UNREGISTER_INI_ENTRIES一遍之后,EG(ini_directives)中只剩下了Core模块的ini配置。此时,就需要手动调用UNREGISTER_INI_ENTRIES,来完成对Core模块配置的删除工作。
复制代码 代码如下:
void php_module_shutdown(TSRMLS_D)
{
...
// zend_shutdown会依次关闭除了Core之外的所有php模块
// 关闭时会调用各个模块的PHP_MSHUTDOWN_FUNCTION
zend_shutdown(TSRMLS_C);
...
// 至此,EG(ini_directives)中只剩下了Core模块的配置
// 这里手动清理一下
UNREGISTER_INI_ENTRIES();
// 回收configuration_hash
php_shutdown_config();
// 回收EG(ini_directives)
zend_ini_shutdown(TSRMLS_C);
...
}
当手动调用UNREGISTER_INI_ENTRIES完成之后,EG(ini_directives)已经不包含任何的元素,理论上讲,此时的EG(ini_directives)是一张空的hash表。
2,configuration_hash的回收发生在EG(ini_directives)之后,上面贴出的代码中有关于php_shutdown_config的函数调用。php_shutdown_config主要负责回收configuration_hash。
复制代码 代码如下:
int php_shutdown_config(void)
{
// 回收configuration_hash
zend_hash_destroy(&configuration_hash);
...
return SUCCESS;
}
注意zend_hash_destroy并不会释放configuration_hash本身的空间,同XXX_G访问的模块全局空间一样,configuration_hash也是一个全局变量,无需手动回收。
3,当php_shutdown_config完成时,只剩下EG(ini_directives)的自身空间还没被释放。因此最后一步调用zend_ini_shutdown。zend_ini_shutdown用于释放EG(ini_directives)。在前文已经提到,此时的EG(ini_directives)理论上是一张空的hash表,因此该HashTable本身所占用的空间需要被释放。
复制代码 代码如下:
ZEND_API int zend_ini_shutdown(TSRMLS_D)
{
// EG(ini_directives)是动态分配出的空间,需要回收
zend_hash_destroy(EG(ini_directives));
free(EG(ini_directives));
return SUCCESS;
}