Você não pode calcular retrospectivamente a pegada exata de uma variável, pois duas variáveis podem compartilhar o mesmo espaço alocado na memória
Vamos tentar compartilhar memória entre dois arrays, vemos que alocar o segundo array custa metade da memória do primeiro. Quando removemos o primeiro, quase toda a memória ainda é usada pelo segundo.
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)
Portanto, não podemos concluir que o segundo array usa metade da memória, pois torna-se falso quando removemos o primeiro.
Para uma visão completa sobre como a memória é alocada no PHP e para qual uso, sugiro que você leia o seguinte artigo: Qual o tamanho real dos arrays (e valores) do PHP? (Dica: GRANDE!)
O Reference Counting Basics na documentação do PHP também contém muitas informações sobre o uso de memória e contagem de referências para segmentos de dados compartilhados.
As diferentes soluções expostas aqui são boas para aproximações, mas nenhuma pode lidar com o gerenciamento sutil de memória PHP.
- calcular o espaço recém-alocado
Se você quiser o espaço recém-alocado após uma atribuição, terá que usá-lo memory_get_usage()
antes e depois da alocação, pois usá-lo com uma cópia lhe dá uma visão errônea da realidade.
// 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";
Lembre-se de que se você quiser armazenar o resultado da primeira memory_get_usage()
, a variável já deve existir antes e memory_get_usage()
deve ser chamada outra vez, e também todas as outras funções.
Se você quiser ecoar como no exemplo acima, seu buffer de saída já deve estar aberto para evitar a memória de contabilidade necessária para abrir o buffer de saída.
- calculando o espaço necessário
Se você quiser contar com uma função para calcular o espaço necessário para armazenar uma cópia de uma variável, o código a seguir cuida de diferentes otimizações:
<?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
Observe que o tamanho do nome da variável é importante na memória alocada.
- Verifique seu código !!
Uma variável tem um tamanho básico definido pela estrutura interna C usada no código-fonte do PHP. Este tamanho não varia no caso de números. Para strings, adicionaria o comprimento da string.
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;
Se não levarmos em consideração a inicialização do nome da variável, já sabemos quanto uma variável usa (no caso de números e strings):
44 bytes no caso de números
+ 24 bytes no caso de strings
+ o comprimento da string (incluindo o caractere NUL final)
(esses números podem mudar dependendo da versão do PHP)
Você deve arredondar para um múltiplo de 4 bytes devido ao alinhamento da memória. Se a variável estiver no espaço global (não dentro de uma função), ela também alocará mais 64 bytes.
Portanto, se você quiser usar um dos códigos dentro desta página, você deve verificar se o resultado usando alguns casos de teste simples (strings ou números) correspondem a esses dados levando em consideração cada uma das indicações neste artigo ($ _GLOBAL array, primeira chamada de função, buffer de saída, ...)