我的一位同事写了一个耗尽可用内存的脚本。我将其缩小到以下基本测试用例:
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,所以循环引用不能成为这个问题的原因。
答案 0 :(得分:4)
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指出我正确的方向!