如果我有循环引用,我能自动触发PHP垃圾收集吗?
我似乎想起了一种为类设置如果我有循环引用,我能自动触发PHP垃圾收集吗?,php,garbage-collection,circular-reference,Php,Garbage Collection,Circular Reference,我似乎想起了一种为类设置\uuu destruct的方法,这种方法可以确保一旦外部对象超出范围,循环引用就会被清除。然而,我构建的简单测试似乎表明这并不像我预期的那样 有没有一种方法可以设置我的类,使PHP能够在最外层的对象超出范围时正确地清理它们 我不是在寻找写这段代码的替代方法,我在寻找是否可以做到这一点,如果可以,如何做到?我通常尽量避免这些类型的循环引用 class Bar { private $foo; public function __construct($foo)
\uuu 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
[ 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<5.3相关的答案,因为它实际上与我的项目(PHP5.2.x)相关。自5.3以来一个解决方案可以是,使用PHP>=5.3,使用手册部分中解释的内容 特别是,gc_*函数可能会引起人们的兴趣——请参见
对于您发布的代码部分,PHP>=5.3:
- 垃圾收集应该是有效的
- 但是它只会在PHP认为有必要时运行李>
- 好的,这将释放一点内存
- 但这是不必要的,因为反正还有很多内存
不久前我在我的博客上写了一篇关于这一点的文章,在那里我做了一些测试;它是用法语写的,但是中的图表(这里没有语言障碍)清楚地显示了垃圾收集器在需要时偶尔运行一次。如果PHP>=5.3,可以使用本手册部分中解释的解决方案 特别是,gc_*函数可能会引起人们的兴趣——请参见
对于您发布的代码部分,PHP>=5.3:
- 垃圾收集应该是有效的
- 但是它只会在PHP认为有必要时运行李>
- 好的,这将释放一点内存
- 但这是不必要的,因为反正还有很多内存
不久前我在我的博客上写了一篇关于这一点的文章,在那里我做了一些测试;它是法语的,但是中的图表(这里没有语言障碍)清楚地显示垃圾收集器在需要时偶尔运行一次。: 当打开垃圾回收器时,只要根缓冲区运行满,就会执行如上所述的循环查找算法。根缓冲区的固定大小为10000个可能的根(尽管您可以通过更改PHP源代码中Zend/Zend_GC.c中的GC_root_buffer_MAX_ENTRIES常量并重新编译PHP来更改此大小)。当垃圾收集器关闭时,循环查找算法将永远不会运行。但是,无论垃圾收集机制是否已使用此配置设置激活,可能的根都将始终记录在根缓冲区中。 : 首先,实现垃圾收集机制的全部原因是在满足先决条件后立即清除循环引用变量,从而减少内存使用。在PHP实现中,当根缓冲区已满或调用函数时,就会发生这种情况。: 当打开垃圾回收器时,只要根缓冲区运行满,就会执行如上所述的循环查找算法。根缓冲区的固定大小为10000个可能的根(尽管您可以通过更改PHP源代码中Zend/Zend_GC.c中的GC_root_buffer_MAX_ENTRIES常量并重新编译PHP来更改此大小)。当垃圾收集器关闭时,循环查找算法将永远不会运行。但是,无论垃圾收集机制是否已使用此配置设置激活,可能的根都将始终记录在根缓冲区中。 :
首先,实现垃圾收集机制的全部原因是在满足先决条件后立即清除循环引用变量,从而减少内存使用。在PHP的实现中,当根缓冲区已满或调用函数时,就会发生这种情况。因为只有在回收对象时才会调用
\uu 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,因为只有在回收对象时才会调用
\u 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注意,“根缓冲区已满”是循环查找算法的唯一自动触发器。例如,当内存限制即将达到时,它将不会运行。因此,当达到内存限制时,脚本仍然可以中止,这只是因为在这种情况下,PHP太笨,无法收集循环!请注意,“根缓冲区已满”是循环查找算法的唯一自动触发器。例如,当内存限制即将达到时,它将不会运行。因此,当达到内存限制时,脚本仍然可以中止,这仅仅是因为PHP太笨而无法运行