Monday, August 8, 2011

understanding PHP memory management

Let's keep exploring how PHP manages memory. Let's check this code and the output():

<?php
var_dump(memory_get_usage());
$name = 'henry';
var_dump(memory_get_usage());
unset($name);
var_dump(memory_get_usage());
?>

The output:

int(325496)
int(325672)
int(325532)

The first output tells us the memory usage is 325496. After we assign a value to a variable $name, the memory usage becomes 325672. The interesting part is the following code: unset($name),  which is supposed to release the memory taken by $name. But the output tells us, the memory usage after we unset($name) is 325532. But,
325496 - 325532 = -36. We still use 36 more memory even we unset($name)!

So, the question comes. Where does the 36 more memory go? Does unset truly release memory? Before we analyse this question in detail, I hope you stand firm with this answer: yes, unset really can release memory, no doubt about that(Surely it also depends on the zval.refcount, see this post: http://hengrui-li.blogspot.com/2011/08/php-copy-on-write-how-php-manages.html ).

Now let's see how PHP allocates memory. For a simple statement $name = 'henry', PHP will do at least two things: 1. PHP allocates memory for the name of the variable, which is '$name', and save it into a symbol table; 2. PHP allocates memory for the value of the variable, which is 'henry', and create a zval to save the value.

However, we must know this: When PHP is trying to ask memory from OS, it won't simply ask memory for its current task only. It will actually ask a large amount of memory(more than what it needs for the moment) from OS, and then allocate a small part of this 'large amount of memory'  to handle its current task. The benefit of asking large amount of memory at the beginning is, if PHP needs to allocate more memory later, it doesn't have to ask from OS again, and this avoids frequent system calling between PHP and OS.

When we do unset($name), PHP will release the memory. But it doesn't mean PHP will return the memory to OS. Actually, PHP will make the memory as its own spare memory that it can allocate to others if necessary.

Let's check this code:

<?php
var_dump(memory_get_usage(true));
$name = 'henry';
var_dump(memory_get_usage(true));
unset($name);
var_dump(memory_get_usage(true));
?>

Note memory_get_usage(true) means we want to get the real size of memory allocated from system. Now the output:

int(524288)
int(524288)
int(524288)

This output tells us one thing: when we do $name = 'henry', PHP does NOT ask more memory from OS.  

Now, let's answer the question at the beginning, where does the 36 more memory go? Let's check this code:

<?php
var_dump("dumping");
var_dump(memory_get_usage());
$name = 'henry';
var_dump(memory_get_usage());
unset($name);
var_dump(memory_get_usage());
?>

The output:

string(7) "dumping"
int(326668)
int(326808)
int(326668)

This time, 326668 - 326668 = 0. It is normal now. Memory allocation in PHP is quite implicitly, sometime it is hard for us to imagine. We var_dump("dumping"); at the beginning and everything looks normal now. This tells us, the 36 memory is taken by the output function. More precisely, the 36 memory is taken by the Header of the output.

No comments: