• 【黄啊码】垃圾回收可以赚钱,那php的垃圾回收机制你懂多少?


    大家好,我是黄啊码,相信java的垃圾回收机制,任何java入门的码农们多多少少已经接触过了,那么php的垃圾回收机制又有多少知道,知道的评论区打个1呗。

    好了,废话不多说,开干!!!

    目录

    什么是垃圾回收?

    php为什么需要垃圾回收?

    Java和PHP的垃圾回收机制对比:

    我们这里只讲两个大版本的php回收机制【php5和php7】

    1、php5和php7的垃圾回收机制都是利用引用计数

    2、php5和php7的垃圾回收机制异同:

    3、变量在zval的变量容器中结构

    PHP5.3标量在zval容器例子

     PHP7.X 标量在zval容器例子

    最后备注说明:

    垃圾回收对性能的影响

    什么是垃圾回收?

    "回收旧手机,旧热水器,旧手表。。。"是这个吗?你要这么说,我一定会问:这是干垃圾还是湿垃圾?哈哈。pia,清醒点把你,咱们这是在说编程语言,在使用 C 语言的时候,我们都要手动使用 free 来释放内存,在 C 之后的大部分编程语言都会自带一个垃圾回收之类的处理能力,也就是我们今天要说的垃圾回收机制,也称为 GC 。在有 GC 能力的开发语言中,我们不需要去关心什么时候释放内存,甚至我们完全不需要去了解这一块的内容,因为这些语言在底层已经帮我们处理好了关于内存释放的问题。

    php为什么需要垃圾回收?

    我们的开发者在不断地操作内存。相应地,如果我们继续增加新变量,内存将继续增加,如果没有良好的机制,内存将无限制地增加,最终填满所有内存。这会导致内存泄漏。但是,在日常开发中,除非一次性加载大文件,否则很少看到内存溢出错误。这就是垃圾收集机制的作用。


    Java和PHP的垃圾回收机制对比:

    Java 种的垃圾回收机制,大家肯定都有所了解,比如如何确定垃圾,有两种算法,引用计数法和可达性分析算法。Java 中使用的是可达性分析算法,而 PHP 使用的引用计数算法。我们都知道引用计数算法较难处理循环引用的问题,PHP 这波奇怪的操作可太秀了,那 PHP 的垃圾回收原理是怎么样的?

    我们这里只讲两个大版本的php回收机制【php5和php7】

    1、php5和php7的垃圾回收机制都是利用引用计数

    原理: 给对象添加一个引用计数器,每当有一个地方引用它,计数器的值就加一。每当有一个引用失效,计数器的值就减一。

    如果一个变量 value 的 refcount 减一之后等于 0,此 value 可以被释放掉,不属于垃圾。垃圾回收器不会处理 。

    如果一个变量 value 的 refcount 减一之后还是大于 0,此 value 被认为不能被释放掉,可能成为一个垃圾。

    垃圾回收器将可能的垃圾收集起来,等达到一定数量后开始启动垃圾鉴定程序,把真正的垃圾释放掉。

    2、php5和php7的垃圾回收机制异同:

    • PHP5标量数据类型会计数,PHP7标量数据类型不再计数,不需要单独分配内存
    • PHP7的zval 需要的内存不再是单独从堆上分配,不再自己存储引用计数。
    • PHP7的复杂数据类型(比如数组和对象)的引用计数由其自身来存储。

    3、变量在zval的变量容器中结构

    zval中,除了存储变量的类型和值之外,还有is_ref字段和refcount字段
        1、is_ref:是个bool值,用来区分变量是否属于引用集合。
        2、refcount:计数器,表示指向这个zval变量容器的变量个数。  

    PHP5.3标量在zval容器例子

     注意:php5.3中将一个变量 = 赋值给另一个变量时,不会立即为新变量分配内存空间,而是在原变量的zval中给refcount加1。 只有当原变量或者发生改变时,才会为新变量分配内存空间,同时原变量的refcount减 1 。

    当然,如果unset原变量,新变量直接就使用原变量的zval而不是重新分配。&引用赋值时,原变量的is_ref  加1.  如果给一个变量&赋值,之前 = 赋值的变量会分配空间。

    1. <?php
    2. $a = 1;
    3. xdebug_debug_zval('a');
    4. echo PHP_EOL;
    5. $b = $a;
    6. xdebug_debug_zval('a');
    7. echo PHP_EOL;
    8. $c = &$a;
    9. xdebug_debug_zval('a');
    10. echo PHP_EOL;
    11. xdebug_debug_zval('b');
    12. echo PHP_EOL;结果如下:
    13. a:(refcount=1, is_ref=0),int 1
    14. a:(refcount=2, is_ref=0),int 1
    15. a:(refcount=2, is_ref=1),int 1
    16. b:(refcount=1, is_ref=0),int 1

     PHP7.X 标量在zval容器例子

    1. $a = 1;
    2. xdebug_debug_zval('a');
    3. echo PHP_EOL;
    4. $b = $a;
    5. xdebug_debug_zval('a');结果如下:可以看到标量(布尔,字符串,整形,浮点型)不再计数了

    最后备注说明:

    说明:在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,如果refcount为0,那么变量的空间可以被释放,否则就不释放,这是一种非常简单的GC实现。现在unset ($a),那么array的refcount减1变为1.现在无任何变量指向这个zval,而且这个zval的计数器为1,不会回收。

    结果:尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于子元素“1”仍然指向数组本身,所以这个容器不能被清除 。因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。

    在php5.3的GC中,针对的垃圾做了如下说明:
        1:如果一个zval的refcount增加,那么此zval还在使用,肯定不是垃圾,不会进入缓冲区
        2:如果一个zval的refcount减少到0, 那么zval会被立即释放掉,不属于GC要处理的垃圾对象,不会进入缓冲区。
        3:如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾,将其放入缓冲区。PHP5.3中的GC针对的就是这种zval进行的处理。

    开启/关闭:垃圾回收机制可以通过修改php配置实现,也可以在程序中使用gc_enable() 和 gc_disable()开启和关闭。

    垃圾回收对性能的影响

    前文说过,垃圾回收在根缓冲区满了之后会马上执行。其中也会进行两次的深度遍历,这就不可避免的带来了性能的消耗。毕竟算法的执行都是需要耗时的。不过相对于内存溢出这种毁灭性的错误来说,垃圾回收带来的性能损耗基本上是可以忽略不计的。

    好了,今天的课程学到这里,有问题的留个言,别忘了一键三连,下次我们还会再见!

    我是黄啊码,码字的码,退。。。退。。。退。。。朝! 

  • 相关阅读:
    【js】 lodash命名转换和封装
    Java Annotation Processor注解处理器如何Debug
    常见的 web 安全问题总结
    carsim 2020 安装说明及多个版本冲突问题解决
    2024最新版JavaScript逆向爬虫教程-------基础篇之深入JavaScript运行原理以及内存管理
    WPF使用Dispatcher
    174. 地下城游戏 -- 动规
    yolov5检测cs2中的目标
    Springboot+JPA+ORACLE12C项目hibernate生成的SQL语句中schema."小写表名"导致的“ORA-00942 表或视图不存在”问题,求解决方案。
    Vue2知识总结
  • 原文地址:https://blog.csdn.net/TiaoZhanJi_Xian/article/details/127704555