Как стать автором
Обновить

Комментарии 6

ей-богу не знаю, что за 32 байта остаются занятыми, должно быть 0 (напишите, если вы в курсе в комментариях)

Переменная $baseMemory...

<?php

function doSmth(int $baseMemory): void {
  $array = range(0, 99);
  printf('memory: %s%s', memory_get_usage() - $baseMemory, PHP_EOL);
}

$baseMemory = memory_get_usage();

echo 'memory before: ', memory_get_usage(), PHP_EOL;
doSmth($baseMemory);
echo 'memory: ', memory_get_usage() - $baseMemory, PHP_EOL;
unset($baseMemory);
echo 'memory after: ', memory_get_usage(), PHP_EOL;
memory before: 388224
memory: 2648
memory: 32
memory after: 388224

..., но был не прав и присоединяюсь к вопросу.

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

С unset функции я тоже был не прав. Видимо тайна кроется в том где в коде будет вызвана memory_get_usage в первый раз. Если переместить определение переменной $baseMemory до определения функции, то в расчете будет 0.

Смотрю в исходники, но мало что понимаю, всё же в С у меня экспертизы недостаточно

Мне кажется это связано как-то с выводом.
Первый вызов echo c не пустой строкой увеличивает память на 32.

Не знаю как обрабатывается echo, но если передавать аргументы через запятую, то складывается ощущение, что echo выводит каждый аргумент по отдельности.

Если же сначала сделать вычисления, то магия не работает.

$baseMemory = memory_get_usage();
$arr = range(0, 99);
unset($arr);
echo 'memory: ', memory_get_usage() - $baseMemory; // memory: 32

$baseMemory = memory_get_usage();
$arr = range(0, 99);
unset($arr);
echo '', memory_get_usage() - $baseMemory; // 0

$baseMemory = memory_get_usage();
$arr = range(0, 99);
unset($arr);
echo 'memory: ' . (memory_get_usage() - $baseMemory); // memory: 0

$baseMemory = memory_get_usage();
$arr = range(0, 99);
unset($arr);
echo memory_get_usage() - $baseMemory, ' - memory'; // 0 - memory

Запятые не играю роли, в исходном примере заменил printf() и запятые в echo:

<?php

function doSmth(int $mem): void {
  $array = range(0, 99);
  echo 'memory in function: ' . memory_get_usage() - $mem . PHP_EOL;
}

// Сначала инициализируем переменную $mem
$mem = memory_get_usage(); echo 'init $mem' . PHP_EOL;
echo 'memory before use: ' . memory_get_usage() . PHP_EOL;

doSmth($mem); 
echo 'memory after use: ' . memory_get_usage() - $mem . PHP_EOL;
➜  ~ php index.php
init $mem
memory before use: 396096
memory in function: 2648
memory after use: 32
➜  ~ 

Теперь меняем местами строку в которой инициализируем $mem и следующую, где выводим значение memory_get_usage()

<?php

function doSmth(int $mem): void {
  $array = range(0, 99);
  echo 'memory in function: ' . memory_get_usage() - $mem . PHP_EOL;
}

// Сначала выводим значение memory_get_usage()
echo 'memory before use: ' . memory_get_usage() . PHP_EOL;
$mem = memory_get_usage(); echo 'init $mem' . PHP_EOL;

doSmth($mem); 
echo 'memory after use: ' . memory_get_usage() - $mem . PHP_EOL;
➜  ~ php index.php
memory before use: 396064
init $mem
memory in function: 2616
memory after use: 0
➜  ~ 

https://3v4l.org/bZHPv/vld — Пример где сначала инициализируем переменную
https://3v4l.org/039Fh/vld — Пример где сначала выводим значение memory_get_usage

https://www.diffchecker.com/Zn9rPop5/ — diff op'кодов

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

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

// условно занято памяти 0
// $mem1 = 0                    +32        
$mem1 = memory_get_usage(); echo 'init $mem1' . PHP_EOL;
//                               32     
echo 'memory before use: ' . memory_get_usage() . PHP_EOL;
// $mem2 = 32                           
$mem2 = memory_get_usage(); echo 'init $mem2' . PHP_EOL;

//                                            32 - 0 
echo 'memory after use ($mem1): ' . memory_get_usage() - $mem1 . PHP_EOL;
//                                            32 - 32 
echo 'memory after use ($mem2): ' . memory_get_usage() - $mem2 . PHP_EOL;
init $mem1
memory before use: 399248
init $mem2
memory after use ($mem1): 32
memory after use ($mem2): 0

Т.е. memory_get_usage() после echo будет содержать значение на 32 больше, чем если бы memory_get_usage() вызывалось до любого вывода.

Что же касается запятой, то вот пример.

echo 'memory :' , memory_get_usage() . PHP_EOL;	
echo 'memory :' , memory_get_usage() . PHP_EOL;	
echo 'memory :' , memory_get_usage() . PHP_EOL;	
memory :386512
memory :386512
memory :386512

Но если заменить запятую на конкатенацию

memory :386480 
memory :386512 
memory :386512

Получается, что при использовании запятой в echo, каждый аргумент выводится по отдельности, а не конкатенирует "внутри" echo.

Мои наблюдения не точны?

Кстати, если включить захват буфера ob_start(), то конечный результат в обоих случаях будет:

memory after use: 0

у меня не было желания спорить, но точки с запятыми в выводе результат в поток — роли не играют конкретно в этом случае. Тем не менее, если посмотреть ОП-коды, да, запятые ведут к "эхо" для каждого аргумента переданному через запятую.

https://3v4l.org/bZHPv - пример (который был выше) с точками
https://3v4l.org/6cU5f - тот же код, но с запятыми

В обоих случаях погрешность в 32 байта.

Вопрос в том, как себя memory_get_usage ведет. Ощущение такое, что первый вызов инициализирует счетчик, который дальше по коду переиспользуется. В случае присвоения — мы в переменной получаем результат до того как будет инициализирована переменная, а дальше получаем ту самую погрешность в 32 байта.

Жаль что у меня это только на уровне догадок, как уже выше писал, компетенций в СИ у меня малова-то чтобы свободно читать исходники php

типа:


<?php

$mem = memory_get_usage(); // запишем в новую переменную значение памяти без учета переменной

и


<?php
echo memory_get_usage(); // снача стартуем "счетчик" и выводим в поток
$mem = memory_get_usage(); // потом записываем значение... почему тут идет учет переменной, и есть загадка :)

Кстати, просто вызов функции в никуда — не помогает в приведении результата к 0. Так что буфер вывода вполне может быть одним из путей к верному ответу.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации