zoukankan      html  css  js  c++  java
  • PHP 垃圾回收机制

    PHP垃圾回收说到底是对变量及其所关联内存对象的操作,

      所以在讨论PHP的垃圾回收机制之前,先简要介绍PHP中变量及其内存对象的内部表示(其C源代码中的表示)。

      PHP官方文档中将PHP中的变量划分为两类:标量类型和复杂类型。

        标量类型包括布尔型、整型、浮点型和字符串;

        复杂类型包括数组、对象和资源;

        还有一个NULL比较特殊,它不划分为任何类型,而是单独成为一类。

    PHP5.2中使用的内存回收算法是大名鼎鼎的Reference Counting,

        这个算法中文翻译叫做“引用计数”,其思想非常直观和简洁:

        为每个内存对象分配一个计数器,当一个内存对象建立时计数器初始化为1(因此此时总是有一个变量引用此对象),

        以后每有一个新变量引用此内存对象,则计数器加1,而每当减少一个引用此内存对象的变量则计数器减1,

        当垃圾回收机制运作的时候,将所有计数器为0的内存对象销毁并回收其占用的内存。

        而PHP中内存对象就是zval,而计数器就是refcount__gc。

        “引用计数”存在问题,就是当两个或多个对象互相引用形成环状后,

        内存对象的计数器则不会消减为0;

        这时候,这一组内存对象已经没用了,但是不能回收,从而导致内存泄露;

    php5.3开始,使用了新的垃圾回收机制,

        首先PHP会分配一个固定大小的“根缓冲区”,

        这个缓冲区用于存放固定数量的zval,

        这个数量默认是10,000,

        如果需要修改则需要修改源代码Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES然后重新编译。

        由上文我们可以知道,

        一个zval如果有引用,要么被全局符号表中的符号引用,要么被其它表示复杂类型的zval中的符号引用。

        因此在zval中存在一些可能根(root)。

        这里我们暂且不讨论PHP是如何发现这些可能根的,这是个很复杂的问题,

        总之PHP有办法发现这些可能根zval并将它们投入根缓冲区。

        当根缓冲区满额时,PHP就会执行垃圾回收,此回收算法如下:

        1、对每个根缓冲区中的根zval按照深度优先遍历算法遍历所有能遍历到的zval,

          并将每个zval的refcount减1,同时为了避免对同一zval多次减1

          (因为可能不同的根能遍历到同一个zval),每次对某个zval减1后就对其标记为“已减”。

        2、再次对每个缓冲区中的根zval深度优先遍历,

          如果某个zval的refcount不为0,则对其加1,否则保持其为0。

        3、清空根缓冲区中的所有根(注意是把这些zval从缓冲区中清除而不是销毁它们),

          然后销毁所有refcount为0的zval,并收回其内存。

    如果不能完全理解也没有关系,只需记住PHP5.3的垃圾回收算法有以下几点特性:

      1、并不是每次refcount减少时都进入回收周期,只有根缓冲区满额后在开始垃圾回收。

      2、可以解决循环引用问题。

      3、可以总将内存泄露保持在一个阈值以下。

    与垃圾回收算法相关的PHP配置

      可以通过修改php.ini中的zend.enable_gc来打开或关闭PHP的垃圾回收机制,

      也可以通过调用gc_enable()或gc_disable()打开或关闭PHP的垃圾回收机制。

      在PHP5.3中即使关闭了垃圾回收机制,PHP仍然会记录可能根到根缓冲区,

      只是当根缓冲区满额时,PHP不会自动运行垃圾回收,

      当然,任何时候您都可以通过手工调用gc_collect_cycles()函数强制执行内存回收。

    原文链接http://www.cnblogs.com/leoo2sk/archive/2011/02/27/php-gc.html

  • 相关阅读:
    Android 开发学习进程0.19 webview 的使用
    2020年4到6月—7家公司面试总结(3家已拿offer)
    iOS今日头条第3轮面试回忆
    [搬运]Dart之枚举中使用扩展
    Proguard 常用规则
    shiro安全框架
    Android服务的AIDL跨进程(程序)操作
    Android——服务的实例,银行服务
    Android四大组件之服务————服务的生命周期和启动方式
    Android 程序间的广播和Manifest找不到(解决方法)
  • 原文地址:https://www.cnblogs.com/laowenBlog/p/6067717.html
Copyright © 2011-2022 走看看