PHP的引用计数是什么意思?

本篇文章给大家介绍一下php引用计数。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

PHP的引用计数是什么意思?

什么是引用计数

在PHP的数据结构中,引用计数就是指每一个变量,除了保存了它们的类型和值之外,还额外保存了两个内容,一个是当前这个变量是否被引用,另一个是引用的次数。为什么要多保存这样两个内容呢?当然是为了垃圾回收(GC)。

也就是说,当引用次数为0的时候,这个变量就没有再被使用了,就可以通过 GC 来进行回收,释放占用的内存资源。

任何程序都不能无限制的一直占用着内存资源,过大的内存占用往往会带来一个严重的问题,那就是内存泄露,而 GC 就是PHP底层自动帮我们完成了内存的销毁,而不用像 C 一样必须去手动地 free 。

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

怎么查看引用计数?

我们需要安装 xdebug 扩展,然后使用 xdebug_debug_zval() 函数就可以看到指定内存的详细信息了,比如:

$a = "I am a String";xdebug_debug_zval('a');// a: (refcount=1, is_ref=0)='I am a String'

登录后复制

从上述内容中可以看出,这个 $a 变量的内容是 I am a String 这样一个字符串。而括号中的 refcount 就是引用次数,is_ref 则是说明这个变量是否被引用。我们通过变量赋值来看看这个两个参数是如何变化的。

$b = $a;xdebug_debug_zval('a');// a: (refcount=1, is_ref=0)='I am a String'$b = &$a;xdebug_debug_zval('a');// a: (refcount=2, is_ref=1)='I am a String'

登录后复制

当我们进行普通赋值后,refcount 和 is_ref 没有任何变化,但当我们进行引用赋值后,可以看到 refcount 变成了2,is_ref 变成了1。这也就是说明当前的 $a 变量被引用赋值了,它的内存符号表服务于 $a 和 $b 两个变量。

$c = &$a;xdebug_debug_zval('a');// a: (refcount=3, is_ref=1)='I am a String'unset($c, $b);xdebug_debug_zval('a');// a: (refcount=1, is_ref=1)='I am a String'$b = &$a;$c = &$a;$b = "I am a String new";xdebug_debug_zval('a');// a: (refcount=3, is_ref=1)='I am a String new'unset($a);xdebug_debug_zval('a');// a: no such symbol

登录后复制

继续增加一个 $c 的引用赋值,可以看到 refcount 会继续增加。然后 unset 掉 $b 和 $c 之后,refcount 恢复到了1,不过这时需要注意的是,is_ref 依然还是1,也就是说,这个变量被引用过,这个 is_ref 就会变成1,即使引用的变量都已经 unset 掉了这个值依然不变。

最后我们 unset 掉 $a ,显示的就是 no such symbol 了。当前变量已经被销毁不是一个可以用的符号引用了。(注意,PHP中的变量对应的是内存的符号表,并不是真正的内存地址)

对象的引用计数

和普通类型的变量一样,对象变量也是使用同样的计数规则。

// 对象引用计数class A{}$objA = new A();xdebug_debug_zval('objA');// objA: (refcount=1, is_ref=0)=class A {  }$objB = $objA;xdebug_debug_zval('objA');// objA: (refcount=2, is_ref=0)=class A {  }$objC = $objA;xdebug_debug_zval('objA');// objA: (refcount=3, is_ref=0)=class A {  }unset($objB);class C{}$objC = new C;xdebug_debug_zval('objA');// objA: (refcount=1, is_ref=0)=class A {  }

登录后复制

不过这里需要注意的是,对象的符号表是建立的连接,也就是说,对 $objC 进行重新实例化或者修改为 NULL ,并不会影响 $objA 的内容,这方面的知识我们在之前的 对象赋值在PHP中到底是不是引用? 文章中已经有过说明。对象进行普通赋值操作也是引用类型的符号表赋值,所以我们不需要加 & 符号。

数组的引用计数

// 数组引用计数$arrA = [    'a'=>1,    'b'=>2,];xdebug_debug_zval('arrA');// arrA: (refcount=2, is_ref=0)=array (//     'a' => (refcount=0, is_ref=0)=1, //     'b' => (refcount=0, is_ref=0)=2// )$arrB = $arrA;$arrC = $arrA;xdebug_debug_zval('arrA');// arrA: (refcount=4, is_ref=0)=array (//     'a' => (refcount=0, is_ref=0)=1, //     'b' => (refcount=0, is_ref=0)=2// )unset($arrB);$arrC = ['c'=>3];xdebug_debug_zval('arrA');// arrA: (refcount=2, is_ref=0)=array (//     'a' => (refcount=0, is_ref=0)=1, //     'b' => (refcount=0, is_ref=0)=2// )// 添加一个已经存在的元素$arrA['c'] = &$arrA['a'];xdebug_debug_zval('arrA');// arrA: (refcount=1, is_ref=0)=array (//     'a' => (refcount=2, is_ref=1)=1, //     'b' => (refcount=0, is_ref=0)=2, //     'c' => (refcount=2, is_ref=1)=1// )

登录后复制

调试数组的时候,我们会发现两个比较有意思的事情。

一是数组内部的每个元素又有单独的自己的引用计数。这也比较好理解,每一个数组元素都可以看做是一个单独的变量,但数组就是这堆变量的一个哈希集合。如果在对象中有成员变量的话,也是一样的效果。当数组中的某一个元素被 & 引用赋值给其他变量之后,这个元素的 refcount 会增加,不会影响整个数组的 refcount 。

二是数组默认上来的 refcount 是2。其实这是 PHP7 之后的一种新的特性,当数组定义并初始化后,会将这个数组转变成一个不可变数组(immutable array)。为了和普通数组区分开,这种数组的 refcount 是从2开始起步的。当我们修改一下这个数组中的任何元素后,这个数组就会变回普通数组,也就是 refcount 会变回1。这个大家可以自己尝试下,关于为什么要这样做的问题,官方的解释是为了效率,具体的原理可能还是需要深挖 PHP7 的源码才能知晓。

关于内存泄露需要注意的地方

其实 PHP 在底层已经帮我们做好了 GC 机制就不需要太关心变量的销毁释放问题,但是,千万要注意的是对象或数组中的元素是可以赋值为自身的,也就是说,给某个元素赋值一个自身的引用就变成了循环引用。那么这个对象就基本不太可能会被 GC 自动销毁了。

// 对象循环引用class D{    public $d;}$d = new D;$d->d = $d;xdebug_debug_zval('d');// d: (refcount=2, is_ref=0)=class D { //     public $d = (refcount=2, is_ref=0)=... // }// 数组循环引用$arrA['arrA'] = &$arrA;xdebug_debug_zval('arrA');// arrA: (refcount=2, is_ref=1)=array (//     'a' => (refcount=0, is_ref=0)=1, //     'b' => (refcount=0, is_ref=0)=2, //     'arrA' => (refcount=2, is_ref=1)=...// )

登录后复制

不管是对象还是数组,在打印调试时出现了 … 这样的省略号,那么你的程序中就出现了循环引用。在之前的文章 关于PHP中对象复制的那点事儿 中我们也讲过这个循环引用的问题,所以这个问题应该是我们在日常开发中应该时刻关注的问题。

推荐学习:php视频教程

以上就是PHP的引用计数是什么意思?的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2516357.html

(0)
上一篇 2025年3月5日 15:52:01
下一篇 2025年2月25日 13:47:56

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • PHP如何实现文章分类

    本篇文章给大家介绍一下用php实现文章分类的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。 文章分类:同一个新闻 属于 多个菜单项 。比如某新闻既属于校园新闻又属于机构设置,那么点开校园新闻菜单项可以看到这篇文章,点…

    2025年3月5日
    200
  • php能清除文件内容吗

    php能清除文件内容,其实现方法是:首先创建一个PHP示例文件;然后通过“fopen($path, “r+”);”打开文件;最后通过“if( flock($fh, LOCK_EX) ){…}”方式清除文件…

    2025年3月5日
    200
  • php怎么删除字符中的斜线

    php删除字符中的斜线的方法:首先打开相应的PHP代码文件;然后通过“stripslashes($_POST[‘json’]);”去掉反斜杠;最后进行json_decode即可。 本文操作环境:windows7系统、…

    2025年3月5日
    200
  • php下载excel打不开了怎么办

    php下载excel打不开的解决办法:1、在下载的过程中不要输出任何非文件信息;2、输出的excel格式一定要和后缀名保存一致;3、检查文件是否下载完整即可。 本文操作环境:windows7系统、PHP7.1版,DELL G3电脑 php下…

    2025年3月5日
    200
  • php中的多态什么意思

    php中的多态按字面上意思理解就是“多种形状”,可以理解为多种表现形式,即“一个对外接口,多个内部实现方法”;在面向对象的理论中,多态性是指同一个操作作用于不同的类的实例,将产生不同的执行结果。 本文操作环境:windows7系统、PHP7…

    2025年3月5日
    200
  • php占位符不能用怎么办

    php占位符不能用是因为代码错误,其解决办法:首先打开相应的代码文件;然后将“placeholder “Your name here””修改为“placeholder=”Your name here&#8…

    2025年3月5日
    200
  • PHP怎么实现局部替换

    PHP实现局部替换的方法:1、通过“substr_replace”函数实现局部替换;2、通过自制的星号替换函数“replaceStar($str, $start, $length=0)”实现局部替换。 本文操作环境:windows7系统、P…

    2025年3月5日 编程技术
    200
  • php中产生随机数的两种方式

    在php中为了之制造一些偶然性,我们可能需要将一些变量的值设置为随机的,为了解决这一问题,php中内置了函数rand()、mt_rand()函数来解决这一问题。 首先我们来看一看mt_rand()函数的语法: mt_rand    ( in…

    2025年3月5日
    200
  • php isset怎么检测变量是否设置

    php isset函数的作用就是检测变量是否设置,其语法是“bool isset( mixed var [, mixed var [, …]] )”,如果被检测的变量存在则返回TRUE,否则返回FALSE。 本文操作环境:win…

    2025年3月5日
    200
  • php执行exec权限不足怎么办

    php执行exec权限不足的解决办法:1、修改php脚本有读取及运行gcc文件路径的权限;2、运行此脚本的iis账户不能用默认的账号。 本文操作环境:windows7系统、PHP7.1版,DELL G3电脑 需要注意两方面的权限 一是php…

    2025年3月5日
    200

发表回复

登录后才能评论