Увеличение использования памяти PHP после сброса массивов? - PullRequest
4 голосов
/ 21 августа 2009

Я запускаю приведенный ниже код, не удаляя массивы, а затем сбрасывая массивы, используя PHP

снят с охраной ($ массив здесь)

И номер памяти увеличивается при использовании unset. Есть идеи почему? И еще лучше, как правильно освободить память?

ВНИМАНИЕ: ПОЖАЛУЙСТА, не проповедуйте о предварительной оптимизации, ее зле и прочем, это тест, так что не читайте об этом, пожалуйста, и спасибо.

//show current memory usage BEFORE
echo memory_get_usage() . "\n"; // 57960

//start timer
$start3 = microtime(true);
// arrays for header menu selector
$header_home = array('home'  => true);
$header_users = array('users.online' => true, 'users.location' => true, 'users.featured' => true, 'users.new' => true, 'users.browse' => true, 'users.search' => true, 'users.staff' => true);
$header_forum = array('forum' => true);
$header_more = array('widgets'  => true, 'news'  => true, 'promote'  => true, 'development'  => true, 'bookmarks'  => true, 'about'  => true);
$header_money = array('account.money' => true, 'account.store' => true, 'account.lottery' => true, 'users.top.money' => true);
$header_account = array('account'  => true);
$header_mail = array('mail.inbox' => true, 'mail.sentbox' => true, 'mail.trash' => true, 'bulletins.post' => true, 'bulletins.my' => true, 'bulletins' => true);

//run throught 1,000 iterations
for($i = 0; $i < $iterations; ++$i) {
if(isset($header_home[$p]))
    $current_home = 'current';
else if(isset($header_users[$p]))
    $current_users = 'current';
else if(isset($header_forum[$p]))
    $current_forum = 'current';
else if(isset($header_more[$p]))
    $current_more = 'current';
else if(isset($header_money[$p]))
    $current_money = 'current';
else if(isset($header_account[$p]))
    $current_account = 'current';
else if(isset($header_mail[$p]))
    $current_mail = 'current';
}
//unset the arrays
unset($header_money);
unset($current_home);
unset($current_users);
unset($current_forum);
unset($current_more);
unset($current_account);
unset($current_mail);

//show time
$end3 = microtime(true);
echo number_format($end3 - $start3, 7) . ' Time3 ARRAY<br />';

//show current memory usage AFTER
echo memory_get_usage() . "\n";

Ответы [ 4 ]

10 голосов
/ 21 августа 2009

Я сделал очень быстрый тест, после этого:

  • объявление $iterations = 10; в начале скрипта
  • с использованием $p, а не $i в цикле for (вы используете $p для доступа к элементам массива, а не $i)
  • добавление строки для отображения использованной памяти перед сбросом

Я получаю это, используя PHP 5.3.1 (сегодняшний снимок) :

328616
332176
331728

Три выхода:

  • первый: начало скрипта (тот, который говорит " показывает текущее использование памяти ДО ")
  • второй: тот, который я добавил перед вызовами, чтобы сбросить; сразу после окончания for цикла
  • третий: тот, который вы положили в конец вашего скрипта.

Итак, unsets действительно провоцируют освобождение некоторой памяти, а не увеличение используемой памяти; -)

Но освобождается только довольно небольшая часть выделенной памяти ...


Теперь может возникнуть вопрос: «Что заставляет некоторую память использоваться и не освобождаться, если я вызываю unset для массивов» - на самом деле, это, вероятно, то, что вы сначала имели в виду?

Ну, я полагаю, что сброс самих массивов не заставляет PHP освобождать память, выделенную для элементов внутри массивов ...

Как и в этой заметке на неустановленной странице руководства написано (цитирование):

unset () делает то, что говорит его имя - сбросить переменную. Это не вызывает немедленного освобождения памяти. РНР сборщик мусора сделает это когда смотреть подходит - намеренно, как только эти циклы процессора не нужны, или еще раньше сценарий не хватает памяти, что бы ни происходило первый.

Если вы делаете $ what = null; тогда вы переписываете переменную данные. Вы можете освободить память / сокращается быстрее, но это может украсть процессор циклы из кода, который действительно нужен чем раньше, тем дольше общее время выполнения.

И, на самом деле, это может выглядеть интересно; -)

Тем не менее, выполнение нескольких быстрых тестов не дает ничего интересного; Я полагаю, что мой скрипт / данные недостаточно велики, чтобы заставить PHP освободить неиспользуемую память, или что-то вроде этого ...


Примечание: если я использую gc_collect_cycles (PHP> = 5.3) для принудительного сбора мусора после unsets, это ничего не меняет - я полагаю, это потому, что есть нет «потерянного цикла».


* Кстати: выполнение вашего кода дало мне довольно много уведомлений (например, $ p против $ i); вы разрабатываете с error_reporting, установленным для сообщения уведомлений? *

3 голосов
/ 21 августа 2009

Вы первый вызов memory_get_usage(), прежде чем массивы существуют. Вы должны делать это между созданиями + заполнением ваших массивов и вашими unset() '

Здесь вы видите, что в конце скрипта используется больше памяти, чем в начале.

1 голос
/ 21 августа 2009

Не знаю, имеет ли это какое-то значение, но вы не сбросили $start3, $end3 и все остальные массивы $home_xxx, кроме $home_money.

Также я бы посоветовал сделать эталонный тест более простым. Например, использовать только один массив.

Будьте проще. Это сделает ваш тест / тест более значимым.

EDIT

Просто немного поиграл с этим ..

Первый тест

<?php
$array = array();

echo "START:". memory_get_usage() . "\n";


for ( $i = 0; $i<1000; $i++ ) {
    $array[] = 'foo';
}

echo "BEFORE UNSET: " . memory_get_usage() . "\n";

unset($array);
echo "AFTER UNSET: " . memory_get_usage() . "\n";

sleep(120);
echo "AFTER A WHILE: " . memory_get_usage() . "\n";

Выход:

START:53632
BEFORE UNSET: 146360
AFTER UNSET: 118848
AFTER A WHILE: 118848

Второй тест :

<?php
$array = array();

echo "START:". memory_get_usage() . "\n";


for ( $i = 0; $i<1000; $i++ ) {
    $array[] = 'foo';
}

echo "BEFORE UNSET: " . memory_get_usage() . "\n";

for ( $i = 0; $i<count($array); $i++ ) {
    unset($array[$i]);
}
unset($array);
echo "AFTER UNSET: " . memory_get_usage() . "\n";

Выход:

START:53944
BEFORE UNSET: 146680
AFTER UNSET: 119128

Таким образом, теория, которая отменяет только расписания для сборки мусора, не верна (по крайней мере, в PHP 5.2.8, но опять же они сильно изменились в GC PHP 5.3).

Боюсь, что вы можете сделать гораздо больше, чем просто сбросить: - (

1 голос
/ 21 августа 2009

unset() не является механизмом «принудительной сборки мусора».

Таким образом, вызов unset() не означает, что память, которую держала переменная, мгновенно доступна, это просто означает, что переменная запланирована для сборки мусора. Механизм PHP делает это по собственному расписанию.

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