PHP扩展-生命周期和内存管理
1. PHP源码结构
PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.
ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码;ZE还负责内存管理,变量作用域管理和对PHP函数的调度管理。
PHP Core负责和SAPI层的通信;PHP Core也为safe_mode, open_basedir的检查提供了统一控制层;PHP Core还提供了streams层,用于用户域的文件和网络IO操作。其中SAPI(Server Application Programming Interface)通常包含Nginx,Apache,IIS,CLI,CGI等主机环境。
PHP扩展在ZE和PHP Core的基础上提供对各种常用操作的封装,比如对mysql,redis,memcache,sqlite等的读写,对json,xml文件的解析,对soap,sokcet,curl的网络协议的封装,对加密解密压缩解压缩等的封装,对图像处理的封装等等。有些扩展是从零开始实现某个功能,比如按照redis的通信协议使用C来实现和redis的通信;有些扩展则是通过调用系统已有的库,比如图片处理的gb扩展需要系统本身要安装了相应的gd库。
在PHP源码php-5.6.24/ext中提供了78个扩展。
总之,由ZE和PHP Core提供基础的架构,由EXT(扩展)提供用户域的各种操作。
以php-5.6.24源码为例,ZE对应文件夹php-5.6.24/Zend, PHP Core对应文件夹php-5.6.24/main, 扩展对应文件夹php-5.6.24/ext。
2. PHP扩展的生命周期
PHP在接收到SAPI命令时,首先初始化并启动它的内核子系统,在内核子系统的启动快结束时,PHP开始加载它的扩展代码并对扩展初始化,此时PHP将调用每个模块的初始化例程Module Initialization routine (MINIT)。
MINIT(Module Initialization)
PHP调用MINIT相关例程,使得每个扩展有机会初始化内部变量、分配资源、注册资源处理句柄,以及向ZE注册自己的函数,以便于脚本调用这其中的函数时候ZE知道执行哪些代码
RINIT(Request Initialization)
在模块初始化完成后,PHP等待来自SAPI的请求,当接收到SAPI请求后,由ZE为当前被请求的php脚本创建运行环境,并调用每个扩展的Request Initialization(RINIT)函数,使得每个扩展有机会设定特定的环境变量,根据请求分配资源,或者执行其他任务,如审核。
这里所说的SAPI请求分为两类,一类是Apache, IIS, 和其他成熟的web server SAPIs,他们在启动时PHP先执行了MINIT,之后等待来自用户的页面请求,当收到请求后执行RINIT;另一类SAPI请求则是CGI or CLI SAPIs,PHP在收到这类SAPI请求时,执行完MINIT马上就执行RINIT。
当RINIT请求初始化完毕后,ZE接回控制权并将当前被请求的脚本翻译成tokens, 最终构成opcodes(操作码),opcodes被执行过程中,如果某个opcode要求执行某个扩展函数,这是ZE就会将相关参数绑定到改函数,并将控制权临时交给该函数去执行,直到该函数执行完毕。
RSHUTDOWN(Request Shutdown)
PHP脚本运行结束后,PHP调用每个扩展的请求关闭(RSHUTDOWN)函数以执行最后的清理工作(如将session变量存入磁盘)。接下来,ZE执行清理过程(垃圾收集),有效地对之前的请求期间用到的每个变量执行unset()。
MSHUTDOWN(Module Shutdown)
当RSHUTDOWN完成后,PHP继续等待SAPI的其他文档请求或者是关闭信号。对于CGI和CLI等SAPI,没有“下一个请求”,所以SAPI立刻开始关闭。关闭期间,PHP再次遍历每个扩展,调用其模块关闭(MSHUTDOWN)函数,并最终关闭自己的内核子系统。
GINIT
初始化全局变量
GSHUTDOWN
释放全局变量
MINFO
设置phpinfo模块的信息,phpinfo要等级每个扩展的配置信息
// main/php.h
#define PHP_MINIT ZEND_MODULE_STARTUP_N
#define PHP_MSHUTDOWN ZEND_MODULE_SHUTDOWN_N
#define PHP_RINIT ZEND_MODULE_ACTIVATE_N
#define PHP_RSHUTDOWN ZEND_MODULE_DEACTIVATE_N
#define PHP_MINFO ZEND_MODULE_INFO_N
#define PHP_GINIT ZEND_GINIT
#define PHP_GSHUTDOWN ZEND_GSHUTDOWN #define PHP_MINIT_FUNCTION ZEND_MODULE_STARTUP_D
#define PHP_MSHUTDOWN_FUNCTION ZEND_MODULE_SHUTDOWN_D
#define PHP_RINIT_FUNCTION ZEND_MODULE_ACTIVATE_D
#define PHP_RSHUTDOWN_FUNCTION ZEND_MODULE_DEACTIVATE_D
#define PHP_MINFO_FUNCTION ZEND_MODULE_INFO_D
#define PHP_GINIT_FUNCTION ZEND_GINIT_FUNCTION
#define PHP_GSHUTDOWN_FUNCTION ZEND_GSHUTDOWN_FUNCTION
3. PHP扩展的内存管理
ZE在执行自己内部的内存管理时,通过附加的标志来标识某某内存变量是否是持久性的,对于非持久内存,ZE会去清理。但在扩展内部最好还是自己去清理非持久内存,因为扩展自己请求分配的非持久内存,将在长时间内保持为未回收状态,这样与之相关的资源长时间得不到释放。
参考文章:Extension Writing Part I: Introduction to PHP and Zend

PHP扩展-生命周期和内存管理的更多相关文章
- JVM的内存管理、对象的生命周期、内存泄漏
1 JVM内存 分为“堆”.“栈”和“方法区”三个区域,分别用于存储不同的数据 1.1 堆 JVM在其内存空间开辟一个称为”堆”的存储空间,这部分空间用于存储使用new关键字所创建的对象. 1.2 栈 ...
- Activity 生命周期及其栈管理方式
Activity 生命周期 Android 系统用栈的形式管理 Activity , 当新的 Activity 被创建是, 会被放置到栈顶, 这个 Activity 会进入到运行状态, 而前一个 Ac ...
- WebApp中的页面生命周期及路由管理
最近切换到一个新项目,使用的技术栈是Require+Backbone,鉴于对鞋厂webapp框架的了解,发现这个新项目有些缺陷,主要是单纯依赖Backbone造成的,也就是Backbone的好和坏都在 ...
- garbage collection - 垃圾收集 生命周期 跟踪内存使用
Professional.JavaScript.for.Web.Developers.3rd.Edition.Jan.2012 JavaScript is a garbage-collected la ...
- React源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理.本系列文章希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期(C ...
- React 源码剖析系列 - 生命周期的管理艺术
目前,前端领域中 React 势头正盛,很少能够深入剖析内部实现机制和原理. 本系列文章 希望通过剖析 React 源码,理解其内部的实现原理,知其然更要知其所以然. 对于 React,其组件生命周期 ...
- Elasticsearch7.X ILM索引生命周期管理(冷热分离)
Elasticsearch7.X ILM索引生命周期管理(冷热分离) 一.“索引生命周期管理”概述 Elasticsearch索引生命周期管理指:Elasticsearch从设置.创建.打开.关闭.删 ...
- Elasticsearch索引生命周期管理方案
一.前言 在 Elasticsearch 的日常中,有很多如存储 系统日志.行为数据等方面的应用场景,这些场景的特点是数据量非常大,并且随着时间的增长 索引 的数量也会持续增长,然而这些场景基本上只有 ...
- Elasticsearch索引生命周期管理探索
文章转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484130&idx=1&sn=454f199 ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- PHP-生成缩略图和添加水印图-学习笔记
1.开始 在网站上传图片过程,经常用到缩略图功能.这里我自己写了一个图片处理的Image类,能生成缩略图,并且可以添加水印图. 2.如何生成缩略图 生成缩略图,关键的是如何计算缩放比率. 这里,我根据 ...
- Microsoft Loves Linux
微软新任CEO纳德拉提出的“Microsoft Loves Linux”,并且微软宣布.NET框架的开源,近期Microsoft不但宣布了Linux平台的SQL Server,还宣布了Microsof ...
- Android笔记——Button点击事件几种写法
Button点击事件:大概可以分为以下几种: 匿名内部类 定义内部类,实现OnClickListener接口 定义的构造方法 用Activity实现OnClickListener接口 指定Button ...
- lua执行字节码的过程介绍
前面一篇文章中介绍了lua给下面代码生成最终的字节码的整个过程,这次我们来看看lua vm执行这些字节码的过程. foo = "bar" local a, b = "a& ...
- C# 自定义控件VS用户控件
1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...
- WPF中Grid实现网格,表格样式通用类
/// <summary> /// 给Grid添加边框线 /// </summary> /// <param name="grid"></ ...
- Android Fragment 剖析
1.Fragment如何产生?2.什么是Fragment Android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视.针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后 ...
- git如何切换远程仓库
场景 工作时可能由于git仓库的变动,需要我们将已有代码切换仓库.比如我们先用的gitlab,现在要切换到github上. 迁移命令 代码迁移其实也很简单. 先保证本地代码是最新代码 $ git pu ...
- Android代码分析工具lint学习
1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...