未明确设置时过多的对象内存使用量

时间:2011-10-25 13:05:08

标签: php garbage-collection

我的一位同事写了一个耗尽可用内存的脚本。我将其缩小到以下基本测试用例:

for ( $i = 0; $i <= 20; $i ++ ) {
    echo memory_get_usage(). '<br />';
    $Survey = new Survey( 14 );
    echo memory_get_usage(). '<br /><br />';
}
exit('done');

这在第三次迭代时中断:

3116696
49123440

49123440
95518368

95518368
[E_ERROR] Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes)

我设法解决了这个问题,只需在循环中添加unset()调用:

for ( $i = 0; $i <= 20; $i ++ ) {
    echo memory_get_usage(). '<br />';
    $Survey = new Survey( 14 );
    unset( $Survey );
    echo memory_get_usage(). '<br /><br />';
}
exit('done');

现在,脚本经历了20次迭代,非常流畅,内存使用率相对恒定:

3116816
49123488

49123488
50691656

50691656
51088912

51088912
51079064

51079064
50535368

50535368
50809296

50809296
51033392

51033392
51157208

51157208
50543856

50543856
50892760

50892760
51045160

51045160
51132688

51132688
50535968

50535968
50968632

50968632
51058080

51058080
51143304

51143304
50562136

50562136
51067432

51067432
51067768

51067768
51170824

51170824
50551712

done

这让我很困惑!是不是垃圾收集器应该清理对象,因为它的变量已被覆盖?我正在运行PHP 5.3,所以循环引用不能成为这个问题的原因。

2 个答案:

答案 0 :(得分:4)

5.3中的

Circular references can still be a problem

  

清理问题

     

虽然任何范围内都不再有符号指向此符号   结构,因为数组元素“1”仍然无法清理   指向同一个数组。因为没有外部符号   指向它,用户无法清理这个结构;   因此你得到了内存泄漏。幸运的是,PHP将清理这些数据   在请求结束时的结构,但在此之前,这是采取   在记忆中占有宝贵的空间。如果你这种情况经常发生这种情况   实现解析算法或其他有孩子的事情   回到“父”元素。同样的情况也可能发生   当然,对象实际上更容易发生,如   对象总是被引用隐式使用。

Survey内部可能还有一些占用内存的资源占用了所有内存;观察到的行为应该是ref循环和这样的资源的组合。

Survey究竟是什么?

答案 1 :(得分:0)

问题是由循环引用和占用1/3可用内存的对象引起的。将代码更改为:

for ( $i = 0; $i <= 20; $i ++ ) {
    echo memory_get_usage(). '<br />';
    gc_collect_cycles();
    echo memory_get_usage(). '<br />';
    $Survey = new Survey( 14 );
    echo memory_get_usage(). '<br /><br />';
}
exit('done');

告诉我:

3116456
3116680
49123288

49123288
49123288
95518160

95518160
50452344
96236360

96236360
50365776
96261312

96261312
50477296
96348608

96348608
50453072
96349752

96349752
50478440
96364872

96364872
50468192
96365240

96365240
50478808
96370760

96370760
50473712
96366072

96366072
50474120
96371448

96371448
50479088
96375352

96375352
50478024
96376672

96376672
50480408
96374984

96374984
50476336
96373032

96373032
50478456
96372216

96372216
50475520
96371288

96371288
50477528
96378824

96378824
50483056
96383992

96383992
50482696
96376592

96376592
50475656
96378072

done

您可以清楚地看到,手动启动垃圾收集器会释放“孤立”对象占用的内存。我认为问题在于垃圾收集器没有足够的时间进入,因为对象太大了。

现在最简单的解决方案是添加unset()调用 - 但是我将研究如何使Survey对象更具内存效率。

感谢Jon和CodeCaster指出我正确的方向!

相关问题