Memory_Get_Peak_Usage() with "Real Usage"

memory_get_peak_usage() with real usage

Ok, lets test this using a simple script:

ini_set('memory_limit', '1M');
$x = '';
while(true) {
echo "not real: ".(memory_get_peak_usage(false)/1024/1024)." MiB\n";
echo "real: ".(memory_get_peak_usage(true)/1024/1024)." MiB\n\n";
$x .= str_repeat(' ', 1024*25); //store 25kb more to string
}

Output:

not real: 0.73469543457031 MiB
real: 0.75 MiB

not real: 0.75910949707031 MiB
real: 1 MiB

...

not real: 0.95442199707031 MiB
real: 1 MiB

not real: 0.97883605957031 MiB
real: 1 MiB

PHP Fatal error: Allowed memory size of 1048576 bytes exhausted (tried to allocate 793601 bytes) in /home/niko/test.php on line 7

Seems like real usage is the memory allocated from the system - which seems to get allocated in larger buckets than currently needed by the script. (I guess for performance reasons). This is also the memory the php process uses.

The $real_usage = false usage is the memory usage you actually used in your script, not the actual amount of memory allocated by Zend's memory manager.

Read this question for more information.

In short: to get how close are you to the memory limit, use $real_usage = true

What does memory_get_peak_usage(true) do?

This question is a dup, as said above.

However, I think I should summarize my understanding from the different answers and comments:

  • memory_get_peak_usage(false) returns the exact memory used by the PHP script. Use to compare exact memory consumption of different sections of a PHP script.
  • memory_get_peak_usage(true) returns the memory allocated from the system to the PHP script, it's always higher because the Zend engine allocates the memory in 256KB chunks. Use to know the real impact of a given PHP script on the system.

So basically, memory_get_peak_usage(true) should be memory_get_peak_usage(false) rounded to the next 256KB.

Does memory_get_peak_usage() returns memory of the whole php or just the current execution?

It returns the peak usage for the current request only.

From the doc:

Returns the peak of memory, in bytes, that's been allocated to your PHP script.


To remove any ambiguities from the docs:

memory_get_peak_usage() calls the internal zend_memory_peak_usage() function, which returns AG(mm_heap)->peak.

AG(mm_heap)->peak is reset to 0 in zend_mm_shutdown(), which is called in php_request_shutdown() at the end of each request.

So it's the peak memory usage for the current request only.

Tracking Memory Usage in PHP

real_usage works this way:

Zend's memory manager does not use system malloc for every block it needs. Instead, it allocates a big block of system memory (in increments of 256K, can be changed by setting environment variable ZEND_MM_SEG_SIZE) and manages it internally. So, there are two kinds of memory usage:

  1. How much memory the engine took from the OS ("real usage")
  2. How much of this memory was actually used by the application ("internal usage")

Either one of these can be returned by memory_get_usage(). Which one is more useful for you depends on what you are looking into. If you're looking into optimizing your code in specific parts, "internal" might be more useful for you. If you're tracking memory usage globally, "real" would be of more use. memory_limit limits the "real" number, so as soon as all blocks that are permitted by the limit are taken from the system and the memory manager can't allocate a requested block, there the allocation fails. Note that "internal" usage in this case might be less than the limit, but the allocation still could fail because of fragmentation.

Also, if you are using some external memory tracking tool, you can set this
environment variable USE_ZEND_ALLOC=0 which would disable the above mechanism and make the engine always use malloc(). This would have much worse performance but allows you to use malloc-tracking tools.

See also an article about this memory manager, it has some code examples too.

How much memory is PHP actually using?

It should be emphasized what exactly the values reported by ps and memory_get_usage(true) are.

ps -o rss reports the actual Resident Set Size. Relying on this value is quite a pitfall, as it does not include eventually swapped out memory. In general, you want the USS, the Unique Set Size, which is basically unshared memory (have a look at smem(8) for that). It is the amount of unshared memory the kernel actually has mapped pages for that process, i.e. physically present unshared memory in either RAM or swapfiles. This is as close as you can get for "real" memory usage. [Also refer to /proc/$PID/smaps for a detailed overview, as mentioned in the answer by IVO GELOV, where you could technically count the memory you want to count yourself by parsing that virtual file.]

Regarding memory_get_usage(), this reports the heap memory actually allocated by systems using PHP's internal memory manager. This means, libraries which directly use other memory managers of the system (mmap(2) or malloc(3)) do not expose their memory usage here. [This is for example why mysqlnd does show much memory usage while libmysqlclient does not - the latter uses malloc() internally.]

If you pass true as first parameter, i.e. memory_get_usage(true), it returns the total amount of memory PHP's internal memory manager has asked for from the system. This number in general is slightly, but not much higher than memory_get_usage(false). It also is the number which the memory_limit INI setting is compared against.

If you want to see how much workers you can run, note that PHP does not share much memory, except that the kernel may share the library memory and opcache, which shares the structures (opcodes, class info etc.). Thus the shared memory should rather not be important for you. The most important value for you thus should be the USS.

PHP memory_get_usage

According to the php manual, memory_get_usage returns the amount of memory allocated to php, not necessarily the amount being used.



Related Topics



Leave a reply



Submit