代码之家  ›  专栏  ›  技术社区  ›  Beau Simensen

如果我有循环引用,我能自动触发PHP垃圾回收吗?

  •  1
  • Beau Simensen  · 技术社区  · 15 年前

    我好像想起了一种设置 __destruct 对于一个类,它可以确保一旦外部对象超出范围,循环引用就会被清除。然而,我构建的简单测试似乎表明这并不像我预期的那样。

    有没有一种方法来设置我的类,使得当最外层的对象超出范围时,PHP能够正确地清理它们?

    我不是在寻找其他方法来编写这段代码,我是在寻找是否可以这样做,如果可以,如何?我通常尽量避免这些类型的循环引用。

    class Bar {
        private $foo;
        public function __construct($foo) {
            $this->foo = $foo;
        }
        public function __destruct() {
            print "[destroying bar]\n";
            unset($this->foo);
        }
    }
    
    class Foo {
        private $bar;
        public function __construct() {
            $this->bar = new Bar($this);
        }
        public function __destruct() {
            print "[destroying foo]\n";
            unset($this->bar);
        }
    }
    
    function testGarbageCollection() {
        $foo = new Foo();
    }
    
    for ( $i = 0; $i < 25; $i++ ) {
        echo memory_get_usage() . "\n";
        testGarbageCollection();
    }
    

    输出如下所示:

    60440
    61504
    62036
    62564
    63092
    63620
     [ destroying foo ]
     [ destroying bar ]
     [ destroying foo ]
     [ destroying bar ]
     [ destroying foo ]
     [ destroying bar ]
     [ destroying foo ]
     [ destroying bar ]
     [ destroying foo ]
     [ destroying bar ]
    

    60440
     [ destorying foo ]
     [ destorying bar ]
    60440
     [ destorying foo ]
     [ destorying bar ]
    60440
     [ destorying foo ]
     [ destorying bar ]
    60440
     [ destorying foo ]
     [ destorying bar ]
    60440
     [ destorying foo ]
     [ destorying bar ]
    60440
     [ destorying foo ]
     [ destorying bar ]
    

    更新:

    对于这个与PHP有关的问题,有几个很好的答案>5.3,但我选择了一个适用于PHP的答案<因为它实际上与我的项目(php5.2.x)有关。

    4 回复  |  直到 15 年前
        1
  •  2
  •   troelskn    15 年前

    作为 __destruct 只在对象被回收后调用,不能使用它。但是,您可以创建手动清理功能:

    class Foo {
      private $bar;
      public function __construct() {
        $this->bar = new Bar($this);
      }
      public function cleanup() {
        $this->bar = null;
      }
      public function __destruct() {
        print "[destroying foo]\n";
      }
    }
    
    class Bar {
      private $foo;
      public function __construct($foo) {
        $this->foo = $foo;
      }
      public function __destruct() {
        print "[destroying bar]\n";
      }
    }
    
    function testGarbageCollection() {
      $foo = new Foo();
      $foo->cleanup();
    }
    

    我不确定这有多有用,但这确实是您唯一的选择<5.3

        2
  •  3
  •   Pascal MARTIN    15 年前

    解决方案可以是,使用PHP>=5.3,使用 Garbage Collection

    特别是,gc函数可能很有意思——参见 gc_collect_cycles ,等等。


    • 但是 它只会在PHP认为必要时运行 !

    • 但这是不必要的,因为有足够的内存剩余无论如何

    而且,由于垃圾收集需要时间,PHP不会经常运行它。


    前段时间我在博客上写了一篇文章,在那里我做了一些测试;它是法语的,但是图表 在里面 this section

        3
  •  2
  •   VolkerK    15 年前

    http://docs.php.net/features.gc.collecting-cycles :

    根缓冲区的固定大小为10000个可能的根(尽管您可以通过更改PHP源代码中Zend/Zend\u GC.c中的GC\u root\u buffer\u MAX\u ENTRIES常量并重新编译PHP来更改此大小)。 当垃圾收集器关闭时,循环查找算法将永远不会运行。但是,不管垃圾回收机制是否已使用此配置设置激活,可能的根始终会记录在根缓冲区中。

    http://docs.php.net/features.gc.performance-considerations :

    首先,实现垃圾回收机制的全部原因是在满足前提条件后立即清除循环引用变量,从而减少内存使用。在PHP的实现中, 一旦根缓冲区满了,或者函数 gc_collect_cycles() 被称为。
        4
  •  0
  •   Your Common Sense    15 年前

    从5.3开始 you can

    推荐文章