Вы не можете ретроспективно рассчитать точный размер переменной, поскольку две переменные могут совместно использовать одно и то же выделенное пространство в памяти.
Попробуем разделить память между двумя массивами, мы увидим, что выделение второго массива занимает половину памяти первого. Когда мы отключили первый, почти вся память по-прежнему используется вторым.
echo memory_get_usage()."\n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."\n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."\n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."\n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."\n"; // <-- 433200 (-11032)
Таким образом, мы не можем сделать вывод, что второй массив использует половину памяти, так как становится ложным, когда мы сбрасываем первый.
Чтобы получить полное представление о том, как выделяется память в PHP и для чего она используется, я предлагаю вам прочитать следующую статью: Насколько велики на самом деле массивы (и значения) PHP? (Подсказка: БОЛЬШОЙ!)
В разделе « Основы подсчета ссылок» в документации PHP также содержится много информации об использовании памяти и подсчете ссылок на общий сегмент данных.
Представленные здесь различные решения хороши для приближений, но ни одно из них не может справиться с тонким управлением памятью PHP.
- расчет вновь выделенного пространства
Если вам нужно новое выделенное пространство после назначения, вы должны использовать его memory_get_usage()
до и после выделения, так как использование его с копией дает вам ошибочное представление о реальности.
// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();
echo memory_get_usage()."\n";
$c=range(1,100);
echo memory_get_usage()."\n";
Помните, что если вы хотите сохранить результат первого memory_get_usage()
, переменная должна уже существовать раньше и memory_get_usage()
должна вызываться еще раз в предыдущий раз, как и все остальные функции.
Если вы хотите эхо, как в приведенном выше примере, ваш выходной буфер должен быть уже открыт, чтобы избежать учета памяти, необходимой для открытия выходного буфера.
- расчет необходимого пространства
Если вы хотите полагаться на функцию для вычисления необходимого пространства для хранения копии переменной, следующий код позаботится о различных оптимизациях:
<?php
function getMemorySize($value) {
// existing variable with integer value so that the next line
// does not add memory consumption when initiating $start variable
$start=1;
$start=memory_get_usage();
// json functions return less bytes consumptions than serialize
$tmp=json_decode(json_encode($value));
return memory_get_usage() - $start;
}
// open the output buffer, and calls the function one first time
echo ".\n";
getMemorySize(NULL);
// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
// call the function name once
range(1,1);
// we will compare the two values (see comment above about initialization of $start)
$start=1;
$start=memory_get_usage();
$c=range(1,100);
echo memory_get_usage()-$start."\n";
echo getMemorySize($c)."\n";
}
test();
// same result, this works fine.
// 11044
// 11044
Обратите внимание, что размер имени переменной имеет значение в выделенной памяти.
- Проверьте свой код !!
Переменная имеет базовый размер, определяемый внутренней структурой C, используемой в исходном коде PHP. В случае цифр этот размер не меняется. Для строк это добавит длину строки.
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
Если мы не принимаем во внимание инициализацию имени переменной, мы уже знаем, сколько использует переменная (в случае чисел и строк):
44 байта в случае чисел
+ 24 байта в случае строк
+ длина строки (включая последний символ NUL)
(эти числа могут меняться в зависимости от версии PHP)
Вы должны округлить до кратного 4 байта из-за выравнивания памяти. Если переменная находится в глобальном пространстве (не внутри функции), она также выделит еще 64 байта.
Поэтому, если вы хотите использовать один из кодов на этой странице, вы должны проверить, что результат, используя несколько простых тестовых примеров (строки или числа), соответствует этим данным с учетом всех указаний в этом сообщении (массив $ _GLOBAL, первый вызов функции, выходной буфер, ...)