PHP内核——内存管理

PHP中的变量是不需要手动释放的,内核帮我们实现了变量的内训管理,包括内存的分配与回收。本文主要介绍PHP中与内存相关的知识点,包括变量的GC机制、垃圾回收以及底层的内存池实现,除此还有一些线程安全相关的知识点。

变量的自动GC机制

现代高级语言普遍提供了变量的自动GC机制,由语言自己进行管理,这样开发者就无需关注变量的分配与释放。PHP同样实现了这种机制,通过“$”声明变量后,使用完成,内核会自动进行释放。

简单实现方式:函数定义变量时分配一内存,用于保存zval及对应的value结构,在函数返回时再将内存释放,若函数执行阶段,该变量作为参数调用了其他函数或者赋值给了其他变量,则把变量复制一份,这样使得变量间相互独立。

这种方式存在的一个问题是:效率低且内存浪费严重。针对这种问题,提出了下列通用的解决方法。

通用实现:引用+写时复制。PHP变量的内存管理就是这种方式实现的。

  • 引用:当变量赋值、传递时不直接进行深度拷贝,多个变量同时共用一个value,引用计数来记录value被使用的变量数目;
  • 写时复制:当某个变量的value发生改变而无法与其他变量共用value时,通过深度拷贝进行分离value。

引用计数

引用计数用来记录当前有多少个zval只想同一个zval_value。当有新的zval指向这个value时,计数器加1,当zval销毁时,计数器减1。当引用计数为0时,表示此value已经没有被任何变量使用,这是value就可以进行释放了。

注意:PHP7中将引用计数保存在了zval_value中。

写时复制

写时复制在计算机系统中应用非常广泛,只在必要的时候才会进行深度拷贝。换句话说,资源的复制是在需要写入的时候才会进行,在此之前,以只读的方式共享。

回收时机

  • 变量的回收时机:在自动GC机制中,在zval断开value的指向时,如果发现refcount=0,则会直接释放value,这就是变量的回收时机。

    除了GC,PHP也可以通过unset()函数主动销毁一个变量。

垃圾回收

  • 提出的背景:通过引用计数PHP实现了变量的自动GC机制,但是有一种情况是这个机制无法解决的,从而因变量无法回收导致内存始终得不到释放,造成内存泄漏,这种情况指的是循环引用

    循环引用:简单来说,就是变量的内部成员引用了变量自身,比如数组中的某个元素指向了数组,这样一来数组的引用计数中就有一个来自自身成员,当所有的外部引用全部断开时,数组的refcount仍然大于0而得不到释放,而实际上这种变量不可能再被使用了。

  • 垃圾:由于循环引用而导致的无法释放的变量称为垃圾,PHP引入垃圾回收机制来回收这种垃圾。

    注意:首先明确两个准则:

    • 如果一个变量value的refcount减少到0,那么此value可以被释放掉,不属于垃圾;
    • 如果一个变量value的refcount减少之后大于0,那么此value还不能被释放掉,此value可能成为一个垃圾。
  • 复合类型的回收时机:在value的refcount减少之后如果仍然大于0,垃圾回收器会把可能成为垃圾的value收集起来,等达到一定数量后开始启动垃圾鉴定程序,把真正的垃圾释放掉。

    目前垃圾只会出现在array和object这两种类型中,需要注意的是:垃圾回收器判断是否要收集意思垃圾时,并不是根据类型进行判断的,而是与前面介绍的是否用到引用计数一样,用过zval.u1.type_flag进行标识的,只有包含IS_TYPE_COLLECTABLE标识的变量类型才会被收集。

  • 垃圾缓存区:垃圾回收器把收集的可能垃圾保存在一个buffer缓存区,收集的时机是refcount减少时,每次refcount减少都会触发收集动作,如果已收集过就不会重复。

  • 回收算法:既然垃圾是由于成员引用自身引起的,那么就对value的所有成员减一遍引用计数(理解的是:将现有的value的refcount减去目前的所有成员数目),如果结果refcount变为0,则就是表明其引用全部来自自身成员,不会产生垃圾。具体步骤:

    • 步骤(1): 遍历垃圾回收器的buffer缓存区,把当前value标为灰色(zend_refcounted_h.gc_info置为GC_GREY),然后对当前value的成员进行深度优先遍历,把成员value的refcount减1,并且也标为灰色。
    • 步骤(2):重复遍历buffer,检查当前value引用是否为0,为0则表示确实是垃圾,把它标为白色(GC_WHITE),如果不为0则排除了引用全部来自自身成员的可能,表示还有外部引用,并不是垃圾,这时候因为步骤(1)对成员进行了refcount减1操作,需要还原回去,对所有成员进行深度遍历,把成员refcount加1,同时标为黑色。
    • 步骤(3):再次遍历buffer,将并非GC_WHIT的节点从buffer中删除,最终buffer缓存区中全部为真正的垃圾,最后将这些垃圾释放,回收完成。

      垃圾回收器主要通过zend_gc_globals这个结构对垃圾进行管理,收集到的可能成为垃圾的value就保存在这个结构的buf中,及垃圾缓存区。

内存池

  • 提出背景:在C语言中,通常使用malloc进行内存的分配,而频繁地分配、释放内存无疑会产生内存碎片。在PHP中,变量的分配、释放非常频繁,如果所有的变量都通过malloc的方式分配,将会造成严重的性能问题,作为语言级的应用,这种损耗是无法接受的。因此,PHP实现了一套内存池(Zend Memery Manager,ZendMM),用来替换malloc、free,以解决内存频繁分配、释放问题。

  • 内存池的作用

    • 减少内存分配及释放的次数
    • 有效控制内存碎片的产生

内存池是PHP内核中最底层内存操作,它是非常独立的一个模块,可以移植到其他C语言应用中去。

内存池,定义了三种粒度的内存块,如下:

内存块Huge(chunk)Large(page)Small(slot)
内存大小2MB4KB8,16,24,32···3027B(30种)
内存分配策略RM>2MB,直接调用系统分配3092B< RM <2044KBRM<=3092B

此处RM表示申请内存的大小。3092B相当于3/4个page,2044KB相当于511个page。

三种粒度的内存块间的关系:

zendmm

一个或者若干个page可以被分割为多个slot。内存池提前定义好了30种同等大小的内存(8,16,24,32···3027),他们分配在不同的page上(不同大小的内存可能会分配在多个连续的page),申请内存时,直接在对应的page上查找可用的slot。

线程安全

  • 提出背景:在多线程环境中,使用全局变量(声明在函数之外的变量为全局变量)实现多个函数间共享数据,全局变量为各个线程共享,不同的线程引用同一地址空间,如果一个线程修改了全局变量,全局变量就会影响所有的线程。

  • 定义:线程安全指的就是多线程环境下如何安全地获取公共资源。

  • 应用场景:PHP的SAPI多数是单线程环境,比如Cli、Fpm和Cgi,每个进程只启动一个主线程,这种模式下是不存在线程安全问题的,但是也存在多线程环境,如Apache或用户自己嵌入的PHP实现环境,这是就需要考虑线程安全了。PHP通过线程安全资源管理器(Thread Safe Resource Manageer,TSRM),用于解决多线程环境下公共资源冲突问题,实现线程之间安全的操作公共资源。

  • 基本思路:针对共用资源存在的问题,采取各个线程各自复制同一份全局变量,使用数据时各线程各取自己的副本,互不干扰。其核心思想就是为不同的线程分配独立的内存空间。

  • 基本流程:如果一个资源被多个线程使用,首先需要预先想TSRM注册资源,TSRM会为这个资源分配一个唯一的id,并把这种资源的大小、初始化函数等保存到一个tsrm_resource_type结构中,各线程只能通过TSRM分配的那个id访问这个资源。

参考: 秦朋 《PHP7内核剖析》第4章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/242323.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

买房贷款被拒,该如何补救?

买房贷款被拒&#xff0c;想要补救得先找到根源&#xff0c;然后才能对症下药。下面我们就来分析下房贷被拒的原因&#xff0c;以及补救的方法。一、征信不良一般在提交房贷资料之前银行会先查询申请人的信用记录&#xff0c;银行对征信的要求一般是连三累六&#xff0c;也就是…

配置有户名和邮箱

配置有户名和邮箱 按上下键&#xff0c;可以切换到历史命令。 修改信息 获取单独的信息 Git help 就是对各种命令进行查询 对help中的具体命令进行查询

这4种钱没有也要借,不能等

借钱&#xff1f;说起来好像是一件没有面子的事情&#xff0c;但是我们认真观察下人的一生&#xff0c;我们会发现&#xff0c;在不同的时间段&#xff0c;我们会面临各种各样的问题&#xff0c; 我们所处的环境都会不一样&#xff0c;有时候有些钱是必须要花的&#xff0c;即使…

注意:这些信用卡不激活也会产生费用

银监会规定&#xff0c;信用卡未经持卡人激活&#xff0c;不得扣收任何费用。因此很多人都以为信用卡不激活就不会产生费用&#xff0c;挺多留下一个征信查询记录&#xff0c;但这只针对普通的金卡、白金卡的情况&#xff0c;如果你申请的是特种卡、高端白金卡&#xff0c;钻石…

管理git项目

管理git项目 错误示范 第一步&#xff1a;想建立项目文件夹 第二步&#xff1a;进入到项目文件夹下 第三步&#xff1a;在项目文件夹下使用git命令 正确示范 第一步&#xff1a;创建项目文件 第二步&#xff1a;进入到项目文件夹下 第三步&#xff1a;初始化项目文件的…

有人说,如果有条件一定要远离穷人,你赞成吗?

我觉得应该远离穷人的环境及思想&#xff0c;而不是远离穷人。我记得有一位老师说过一句话&#xff1a;“一个人要走多远才能成功&#xff0c;关键是看与谁同行”。当时听这句的时候&#xff0c;觉得挺有哲理的&#xff0c;但并没有理解其中的深意&#xff0c;后来工作了多年之…

信用卡套现只要正常还款,银行是不是睁只眼闭只眼?

这要怎么说呢&#xff0c;目前没有法律规定说持卡人不能套现&#xff0c;套现要分恶意的还是非恶意的套现。只要你能够按时还款&#xff0c;你就是正常的消费&#xff0c;如果你套现之后出现逾期或不还&#xff0c;那你就是恶意套现&#xff0c;对于恶意套现&#xff0c;银行肯…

commit的作用

commit的作用 commit的作用&#xff1a;提交和保持的状态。会产生一个档案号。 没有被追踪时&#xff0c;不能使用commit&#xff08;没有被提交&#xff09;

银行理财不再保本保息,你还敢买吗?

2018年4月27日&#xff0c;《关于规范金融机构资产管理业务的指导意见》正式发布。这个指导意见的发布有几个大家最关心的点&#xff1a;一是银行的理财产品不能承诺保本保收益&#xff1b;二是银行不再承诺刚性兑付。所谓不在承诺保本保收益就是&#xff0c;以后购买银行理财产…

房贷是不是越多越久越好?

从理论上来说&#xff0c;房贷确实是越多、越久越有利&#xff0c;但是在操作的过程中需要根据自己的还款能力来定。为什么房贷越多越久越好&#xff1f;很简单的一个道理&#xff0c;物价每年都在上涨&#xff0c;而房贷不是每年都在涨&#xff0c;除非基准利率调整了才会跟着…

log追踪和追踪文件修改前后的区别

log追踪 :q表示退出 追踪文件修改前后的区别 只要没有git commit&#xff0c;就可以查看修改的区别

Vivado抓取信号

前言1111 FPGA调试需要抓取特定信号&#xff0c;一个直观的思路是&#xff1a;保存抓取的信号&#xff0c;事后分析/ 或者 导出实测数据&#xff0c;用作后续算法仿真验证。 本文简要记录数据的导出及读取。 一、信号导出 &#xff08;1&#xff09;把想要观测的信号线加入在线…

余额宝升级,限额限时解除,以后再也不用定闹钟抢破头了!

余额宝自2014年推出以来深得老百姓的喜欢&#xff0c;目前已经成为普通来百姓的理财神器&#xff0c;但是因为余额宝发展速度太快&#xff0c;累积的风险压力不断增加&#xff0c;所以余额宝一再限额&#xff0c;限购&#xff0c;限时。目前余额宝单个客户限额是10万元&#xf…

如何配置Git环境变量

如何配置Git环境变量 首先找到git的执行文件目录 右击选择属性 进入到bin文件下&#xff0c;复制执行文件路径 D:\git\Git\bin然后&#xff0c;搜索环境变量

征信报告上的逾期记录应该怎么清除?

正常情况下信用逾期是不能清除的&#xff0c;特殊情况除外。正常逾期不能申请消除&#xff0c;只能等时间消除人行征信中心规定&#xff0c;个人不良征信记录的记录时间是5年。但是这个5年是有前提条件的&#xff0c;5年时间是从你还清所有欠款的那天开始算起。比如你信用卡出现…

想创业没有资金,如何获得启动资金?

如果你项目好&#xff0c;就不怕没有资金。我们简单来说下几种创业资金的获取方式&#xff0c;当然不是每一种方式都适合所有人&#xff0c;具体要根据自己的条件来定。第一种&#xff1a;自有资金创业刚开始一般都以自有资金为主&#xff0c;因为你的项目刚起步&#xff0c;没…

比尔盖茨为什么能成为世界首富?

说到比尔盖茨的财富&#xff0c;很多人可能首先想到的是比尔盖茨精明的投资&#xff0c;因为这些年他通过跟巴菲特学投资&#xff0c;光靠投资就带来了超过700亿美元的财富&#xff0c;而微软所带来的财富只占其总财富的1/8左右。但我想说的是&#xff0c;投资确实给比尔盖茨带…

房奴房贷断供,房子真的会被收走吗?

房贷断供银行是无权收走的&#xff0c;但银行可以申请法院拍卖用于偿还欠款。房屋属于个人财产&#xff0c;银行没有权利私自收回房子是个人财产&#xff0c;不是银行财产&#xff0c;所以银行没有权利滥用“私刑”&#xff0c;但是你办理按揭贷款的时候你就已经跟银行建立了债…

一键还原、撤销追踪操作与文件还原

一键 还原 只能还原修改的文件&#xff0c;不能还原新建的文件。 当你发现修改失误时。 第一种方式 第二种&#xff1a;将文件还原到没有修改 当新建了一个文件时 查看状态&#xff0c;发现新建的文件没有被追踪&#xff0c;此时不能使用git check 如果新建的文件添加追…

半年内使用两次借呗就没法申请房贷?

近日杭州一位网友爆料&#xff0c;“千万不要以为互联网借贷可以随便用&#xff0c;哪怕按时还款也会影响贷款。刚刚银行信贷员告诉我&#xff0c;蚂蚁借呗、京东白条、微粒贷等产品&#xff0c;只要在近半年内有2次使用记录&#xff0c;不管还不还都不给我批车贷。”这个消息立…