0

0

PHP之引用计数内存管理机制和垃圾回收机制

不言

不言

发布时间:2018-04-03 16:49:32

|

1490人浏览过

|

来源于php中文网

原创

本篇文章给大家分享了关于php的引用计数内存管理机制和垃圾回收机制 ,有需要带的朋友可以参考一下

引用赋值

$a = 'apple';
$b = &$a;

上述代码中,我将一个字符串赋值给变量a,然后将a的引用赋值给了变量b。显然,这个时候的内存指向应该是这样的:

$a -> 'apple' <- $b

a和b指向了同一块内存区域(变量容器 zval ),我们通过 var_dump($a, $b) 得到 string(5) "apple" string(5) "apple" ,这是我们预期的结果。

unset函数 与 引用计数

unset 函数

假如我想将 'apple' 这个字符串从内存中释放掉。我是这么做的:

unset($a);

但是通过再次打印 $a $b 两变量的信息,我得到了这样的结果:Notice: Undefined variable: astring(5) "apple" 。奇怪,$a $b 指向同一个变量容器,又明明将$a释放了,为什么$b还是'apple'

立即学习PHP免费学习笔记(深入)”;

其实是这样的,unset()只是将一个变量符号a(指针)销毁了,并没有释放掉那个变量容器,所以执行完操作之后,内存指向只是变成了这样:

'apple' <- $b

引用计数

引用计数 (reference count)是每个变量容器中都会存放的一条信息,它表示当前变量容器正被多少个变量符号所引用。

正如之前的例子,unset()并没有释放变量所指向的变量容器,而只是将变量符号销毁了。同时,将变量容器中的 引用计数 减1,当引用计数为0时,也就是说当变量容器不被任何变量引用时,便会触发php的垃圾回收(错误),它便会被释放(正确)。

更正上述的一个小错误: 这种单纯的引用计数方式是 php 5.2 之前的内存管理机制,称不上是垃圾回收机制,垃圾回收机制是 php 5.3 才引入的,垃圾回收机制为的是解决这种单纯的引用计数内存管理机制的缺陷(即 循环引用导致的内存泄漏,下文会进行讲解)

回到正题,我们用代码来验证一下先前的结论:

$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(0),变量容器的引用计数为1,没有释放
$a = 'apple';
$b = &$a;

$before = memory_get_usage();
unset($a, $b);
$after = memory_get_usage();

var_dump($before - $after);  // 结果为int(24),变量容器的引用计数为0,得到释放

直接释放

那要怎样做才能真正释放掉 'apple' 所占用的内存呢?

利用上述方法,我们可以在 unset($a) 之后再 unset($b) ,将变量容器的所有引用都销毁,引用计数减为0了,自然就被释放掉了。

当然,还有更直接的方法:

$a = null;

直接赋值 null 会将 $a 所指向的内存区域置空,并将引用计数归零,内存便被释放。

脚本执行结束后的内存

对于一般的web程序来说(fpm模式下),php的执行是单线程同步阻塞型的,当脚本执行结束之后,脚本内使用的所有内存都会被释放。那么,我们手动去释放内存到底有意义吗?

其实关于这个问题,早有解答,推荐大家看一下鸟哥 @laruence 2012年发表的一篇文章:

SHCCMS网站管理系统-目录导航风格全套系统1.01
SHCCMS网站管理系统-目录导航风格全套系统1.01

SHCCMS(世惠诚企业网站管理系统)是南阳世惠诚科技有限公司负责开发的企业(公司)CMS网站内容管理系统。 主要功能 针对世惠诚企业网站管理而进行开发,该软件可以进行网站制作流程,客户案例,服务器参数,品牌设计,网站建设,新闻动态等操作。软件正在不断扩展应用接口,完善系统数据维护功能。系统还具有数据回收站机制。能对数据进行回收和撤回操作。软件界面设计简洁,美观。其人性化的软件

下载
请手动释放你的资源(Please release resources manually)

引用计数内存管理机制的缺陷:循环引用

现在我们来讲讲之前提到的引用计数内存管理机制的缺陷。

当一个变量容器的引用计数为0时,php会进行垃圾回收。但是,你可想过,有一种情况会导致一个变量容器的引用计数永远不会被减为0,举个例子:

$a = ['one'];
$a[] = &$a;

我们看到,$a数组第二个元素就是它本身。那么,存放数组的这个变量容器的引用计数为2,一个引用是变量a,另一个引用是这个数组的第二个元素 - 索引1

PHP之引用计数内存管理机制和垃圾回收机制

那么,如果这时我们 unset($a) ,存放数组的变量容器的引用计数会减1,但还有1个引用,就是数组的元素 1 ,现在引用结构变成了这样:

PHP之引用计数内存管理机制和垃圾回收机制

由于变量容器的引用计数没有变为0,所以不能被释放,而且这时又没有外部其他变量符号引用它,用户也没有办法去清除这个结构,这时它就会一直驻留在内存之中。

所以如果代码中存在大量的这种结构和操作,最终会导致内存损耗甚至泄漏。这就是 循环引用 带来的内存无法释放的问题。

庆幸的是,fpm模式下,当请求的脚本执行结束,php会释放所有脚本中使用到的内存,包括这个结构。但是,如果是守护进程下的php程序呢?比如swoole。这个php需要解决的急迫问题(已经解决,见下文)。

PHP 5.3.0 引入的同步算法

传统上,像以前的 php 用到的引用计数内存机制,无法处理循环引用的内存泄漏。然而 5.3.0 PHP 使用文章 » 引用计数系统中的同步周期回收(Concurrent Cycle Collection in Reference Counted Systems) 中的同步算法,解决了这个内存泄漏问题,这种算法就是PHP的垃圾回收机制。

具体算法的实现和流程有些许复杂,请阅读官方文档,这里不再赘述,另附上几个算法流程讲解的文章链接,讲得比较直白:

http://php.net/manual/zh/feat... 官方文档
http://www.cnblogs.com/leoo2s...
https://blog.csdn.net/phpkern...

最后,还是引用鸟哥文章的这两段来说明问题:

在PHP5.2以前, PHP使用引用计数(Reference count)来做资源管理, 当一个zval的引用计数为0的时候, 它就会被释放. 虽然存在循环引用(Cycle reference), 但这样的设计对于开发Web脚本来说, 没什么问题, 因为Web脚本的特点和它追求的目标就是执行时间短, 不会长期运行. 对于循环引用造成的资源泄露, 会在请求结束时释放掉. 也就是说, 请求结束时释放资源, 是一种补救措施(backup).

然而, 随着PHP被越来越多的人使用, 就有很多人在一些后台脚本使用PHP, 这些脚本的特点是长期运行, 如果存在循环引用, 导致引用计数无法及时释放不用的资源, 则这个脚本最终会内存耗尽退出.

所以在PHP5.3以后, 我们引入了GC, 也就是说, 我们引入GC是为了解决用户无法解决的问题.


相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

12

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

4

2026.01.30

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

20

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

18

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

19

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

3

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

6

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 10.4万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 11.2万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号