Вы не можете ретроспективно рассчитать точный размер переменной, поскольку две переменные могут совместно использовать одно и то же выделенное пространство в памяти
Давайте попробуем разделить память между двумя массивами, мы видим, что выделение второго массива стоит половину памяти первого. Когда мы сбрасываем первый, почти все память все еще используется вторым.
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 байта в случае чисел
* +1058 * & плюс; 24 байта в случае строк
& плюс; длина строки (включая последний символ NUL)
(эти цифры могут меняться в зависимости от версии PHP)
Вы должны округлить до 4 кратных байтов из-за выравнивания памяти. Если переменная находится в глобальном пространстве (не внутри функции), она также выделит еще 64 байта.
Так что, если вы хотите использовать один из кодов на этой странице, вы должны убедиться, что результат с использованием простых тестовых примеров (строк или чисел) соответствует этим данным с учетом каждого из указаний в этом посте ( _GLOBAL массив, первый вызов функции, выходной буфер, ...)