чрезмерное использование памяти объекта, если явно не отключено - PullRequest
6 голосов
/ 25 октября 2011

Мой коллега написал сценарий, который исчерпал доступную память. Я сузил его до следующего базового теста:

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 ]

4 голосов
/ 25 октября 2011

Круговые ссылки все еще могут быть проблемой в 5.3:

Проблемы с очисткой

Хотя в больше нет символаЛюбая область видимости, указывающая на эту структуру, не может быть очищена, потому что элемент массива «1» все еще указывает на этот же массив.Поскольку на него не указывает внешний символ, пользователь не может очистить эту структуру;таким образом вы получаете утечку памяти.К счастью, PHP очистит эту структуру данных в конце запроса, но до этого это занимает ценное пространство в памяти.Такая ситуация часто случается, если вы реализуете алгоритмы синтаксического анализа или другие вещи, где у вас есть дочерний элемент, указывающий на «родительский» элемент.Конечно, такая же ситуация может случиться и с объектами, где это на самом деле более вероятно, поскольку объекты всегда неявно используются ссылками.

Вероятно, внутри * 1013 также имеется некоторый ресурс, занимающий перебор памяти.* который занимает всю эту память;наблюдаемое поведение должно быть комбинацией цикла ссылки и такого ресурса.

Что именно в Survey точно?

0 голосов
/ 25 октября 2011

Проблема была вызвана сочетанием циклических ссылок и объектов, занимающих по 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 более эффективным для памяти.

Спасибо Джону и CodeCaster за то, что они указали мне правильное направление!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...