How much memory does your PHP script use?
Memory efficiency is not among the first things to learn about PHP, but checking how much memory a PHP script is using can be very useful.
Learning about memory and code optimization is also among the steps I recommend in my free guide to become a better PHP developer.
Keep reading to learn how to check your PHP scripts memory usage and to see some specific examples.
Table of contents
- Why you should check your scripts memory usage
- memory_get_usage() and memory_get_peak_usage()
- The $real_usage argument: how to use it
- How to monitor loops
- How to monitor PHP daemons
- How to get email notifications when too much memory is used
- A caveat: PHP resources (don’t miss this)
- Conclusion

WHY YOU SHOULD CHECK YOUR SCRIPTS MEMORY USAGE
Among web applications requirements, memory efficiency is not usually at the top of the list.
And, generally speaking, that’s fine.
Other factors, like SQL security and authentication good practices, are surely more important.
However, excessive memory consumption can be a real problem.
In fact, memory consumption issues can easily lead to crashes, hard-to-find bugs and even open the door to Denial-of-Service attacks.
This is especially important in high traffic websites, where many concurrent script executions occur and it’s easier for memory-related issues to cause problems.
Before moving to the next part, I suggest you look at the following short video, which explains nicely how memory management works in PHP and gives you some basics tips to optimize your code:
Some kinds of PHP scripts are particularly at risk of excessive memory consumption:
- very complex scripts, especially if including nested loops;
- scripts using external resources like XML files, database result sets and remote connections;
- always-on scripts like PHP daemons.
Of course, memory issues can occur in other kinds of script as well.
But how can you check how much memory your script is using?
It’s easy:
the standard PHP library provides you with two functions that give you that exact information: memory_get_usage() and memory_get_peak_usage().
Let’s see how they work.
[easy-tweet tweet="A tutorial (with examples) on how to check your PHP script memory usage" via="no" hashtags="PHP"]
memory_get_usage() returns the number of bytes used by the script when the function is called.
Similarly, memory_get_peak_usage() returns the maximum amount of memory (again, in bytes) used by the script until the function is called.
For example:
<?php
$big_array = array();
for ($i = 0; $i < 1000000; $i++)
{
$big_array[] = $i;
}
echo 'After building the array.<br>';
print_mem();
unset($big_array);
echo 'After unsetting the array.<br>';
print_mem();
function print_mem()
{
/* Currently used memory */
$mem_usage = memory_get_usage();
/* Peak memory usage */
$mem_peak = memory_get_peak_usage();
echo 'The script is now using: <strong>' . round($mem_usage / 1024) . 'KB</strong> of memory.<br>';
echo 'Peak usage: <strong>' . round($mem_peak / 1024) . 'KB</strong> of memory.<br><br>';
}
On my PC, I get:

As you see, after the array is unset the current memory usage goes down to 370Kb, but the peak usage remains the same.
(If you want to learn how to set up a local PHP environment, see the Getting started chapter of my PHP learning program).
Both functions take an optional boolean argument named $real_usage. Its default value is false.
What’s it’s meaning and when should you set it to true?
Let’s find out.
Would you like to talk with me and other developers about PHP and web development? Join my Facebook Group: Alex PHP café
See you there 🙂
THE $real_usage ARGUMENT: HOW TO USE IT
$real_usage is a boolean argument. Its default value is false for both memory_get_usage() and memory_get_peak_usage().
If this argument is set to true, then the function returns the full amount of memory allocated by the PHP interpreter for the script instead of the memory actually used by the script.
What’s the difference…?

This is how it works:
The PHP interpreter dynamically allocates memory for the script. This memory is allocated in chunks, small pieces of a fixed amount of memory.
When all the allocated memory has been used by the script, the interpreter allocates another chunk.
So:
- first, the interpreter reserves a chunk of memory for the script to use;
- then the script gradually fills it with its data, until the chunk is full;
- if the script needs more memory, the interpreter allocates another chunk of memory;
- repeat…
Therefore, the amount of allocated memory is always a bit bigger than the amount of used memory (how much bigger depends on many factors, including the PHP configuration and the operating system settings).
This is what $real_usage is used for:
- If $real_usage is set to false (the default), then the functions return the used memory only.
- If $real_usage is set to true, then the functions return the whole allocated memory.
The following example shows how the allocated memory grows along with the memory actually used by the script:
<table align="center" valign="top">
<tr>
<td>Used memory</td>
<td>Allocated memory</td>
<td>Difference</td>
</tr>
<?php
$big_array = array();
for ($i = 0; $i < 100000; $i++)
{
$big_array[] = 'aaa' . $i;
if (($i % 7000) == 0)
{
/* With $real_usage = false (the default value) */
$used_mem = round(memory_get_usage(false) / 1024);
/* With $real_usage = true */
$alloc_mem = round(memory_get_usage(true) / 1024);
echo '<tr><td style="color: green; border: 1px solid #888;">' . $used_mem . 'KB</td>';
echo '<td style="color: blue; border: 1px solid #888;">' . $alloc_mem . 'KB</td>';
echo '<td style="color: red; border: 1px solid #888;">' . ($alloc_mem - $used_mem) . 'KB</td></tr>';
}
}
This is the result:

Notice how the used memory (the first column) grows gradually, while the allocated memory (the second column) grows in chunks.
Note:
if you try running this example and get strange results, like the allocated memory being smaller than the used memory, it’s probably because of some caching system.
A way to avoid such problems is to restart the web server right before running the script.
When should you set $real_usage to true?
Here is the rule of thumb:
if you want to see how much system memory your script is using, then you should set $real_usage to true.
Why?
Because the allocated memory, even if it’s not actually used by the script, is still reserved for it and isn’t available for other system processes.
In other words, it is the amount of system RAM reserved for the PHP process.
On the other hand, if you want to profile your PHP script, then it’s better to leave it to false because you will see the memory usage in more detail.
In fact, that way you can see how much memory a specific piece of code is using regardless of how much memory is available to the script as a whole.
Let’s see a couple of examples of how to do this.
HOW TO MONITOR LOOPS
Inside loop structures excessive memory usage can lead to problems, especially if this usage keeps growing after each loop iteration.
If you want to make sure a loop isn’t using too much memory, it’s a good idea to profile it.
How can you do it?
To begin with, you should print the memory usage before and after the loop to check the difference.
If you see that the memory usage is too high, then you should also check inside the loop itself.
The $real_usage parameter is better left to false, because you want to profile your code in detail more than your whole script.
It’s also useful to see how much of the maximum available memory is being used.
A PHP script can use only up to a certain amount of memory. This value is set in the memory_limit variable of the php.ini file (the main PHP configuration file).
You can retrieve that value with the ini_get() function, convert it into bytes and compare it to the script’s memory usage.
Here’s an example:
<?php
$mem_usage = memory_get_usage();
echo 'Memory usage before the loop: <strong>' . round($mem_usage / 1024) . 'KB</strong><br>';
/* Get the memory limit in bytes. */
$mem_limit = get_memory_limit();
echo 'Memory limit: <strong>' . round($mem_limit / 1048576) . 'MB</strong><br>';
$array = array();
for ($i = 0; $i < 100000; $i++)
{
$array[] = $i;
/* Check the memory usage every 10000 iterations. */
if (($i % 10000) == 0)
{
$mem_usage = memory_get_usage();
$limit_perc = $mem_usage * 100 / $mem_limit;
echo 'Memory usage after iteration ' . $i . ': <strong>' . round($mem_usage / 1024) . 'KB</strong> ';
echo '(' . round($limit_perc) . '% of the available memory for the script)<br>';
}
}
$mem_usage = memory_get_usage();
echo 'Memory usage after the loop: <strong>' . round($mem_usage / 1024) . 'KB</strong><br>';
/* Parse the memory_limit variable from the php.ini file. */
function get_memory_limit()
{
$limit_string = ini_get('memory_limit');
$unit = strtolower(mb_substr($limit_string, -1 ));
$bytes = intval(mb_substr($limit_string, 0, -1), 10);
switch ($unit)
{
case 'k':
$bytes *= 1024;
break 1;
case 'm':
$bytes *= 1048576;
break 1;
case 'g':
$bytes *= 1073741824;
break 1;
default:
break 1;
}
return $bytes;
}
HOW TO MONITOR PHP DAEMONS
PHP daemons are never-ending, looping scripts.
They are extremely useful for maintenance and monitoring tasks, like automatic email notification systems and maintenance operations.
Just like any always-on application, PHP daemons too can suffer from memory leaks.
A good practice is to check the memory usage at the beginning of each loop and do something if it turns out to be excessively high.
For example, you can kill or pause the daemon and send a notification email (you will see how to do it in the next chapter).
For this purpose, it’s better to set $real_usage to true, because you are now more interested in how much memory is really been used more than in profiling your script.
Of course, should memory issues occur, you will need to carefully profile the script to see where the problem comes from (for that, it will be better to leave $real_usage to false).
As an example, let’s see how to terminate a daemon if the used memory is more than 50Mb:
<?php
/* Remove the execution time limit */
set_time_limit(0);
/* Iteration interval in seconds */
$sleep_time = 30;
/* Memory limit (50Mb) */
$mem_limit = 52428800;
$array = array();
$iteration = 0;
while (TRUE)
{
$iteration++;
/* Memory check */
if (memory_get_usage(true) >= $mem_limit)
{
echo 'Memory limit exceeded after iteration ' . strval($iteration);
die();
}
/* Sleep for the iteration interval */
sleep($sleep_time);
for ($i = 0; $i < 500000; $i++)
{
$array[] = $i;
}
}
You can also stop the daemon when its memory usage goes beyond certain percentage of the maximum allowed usage.
To do this, you need to compare the memory usage to the memory_limit value, just as you saw in the loop example before.
Here’s the example:
<?php
/* Remove the execution time limit. */
set_time_limit(0);
/* Get the memory limit in bytes. */
$mem_limit = get_memory_limit();
/* Iteration interval in seconds. */
$sleep_time = 5;
/* Max memory usage: 10% of the memory_limit. */
$mem_perc_limit = 20;
$array = array();
$iteration = 0;
while (TRUE)
{
$iteration++;
/* Memory check. */
$mem_usage = memory_get_usage(true);
$perc_usage = $mem_usage * 100 / $mem_limit;
if ($perc_usage >= $mem_perc_limit)
{
echo 'Memory limit exceeded after iteration ' . $iteration . ' (' . round($perc_usage) . '%)';
die();
}
/* Sleep for the iteration interval */
sleep($sleep_time);
for ($i = 0; $i < 500000; $i++)
{
$array[] = $i;
}
}
/* Parse the memory_limit variable from the php.ini file. */
function get_memory_limit()
{
$limit_string = ini_get('memory_limit');
$unit = strtolower(mb_substr($limit_string, -1 ));
$bytes = intval(mb_substr($limit_string, 0, -1), 10);
switch ($unit)
{
case 'k':
$bytes *= 1024;
break 1;
case 'm':
$bytes *= 1048576;
break 1;
case 'g':
$bytes *= 1073741824;
break 1;
default:
break 1;
}
return $bytes;
}
HOT TO GET EMAIL NOTIFICATIONS WHEN TOO MUCH MEMORY IS USED
Sometimes, debugging and profiling a PHP script’s memory usage can be difficult.
It’s not always easy to retrieve the output from memory_get_usage() and memory_get_peak_usage(), especially when the memory usage depends on the request string values and other factors.
In some cases, memory issues may arise only under specific circumstances or only after some time (especially in PHP daemons).
Just echoing the memory usage isn’t always good enough.
You can’t just stare at your screen waiting for a memory leak to happen, right?

One solution is to log the memory usage information to a log file or a database.
But this solution isn’t perfect either, because you will end up with tons of logs that you need to read and manage.
A smarter solution is to make PHP do the hard work.
Instead of printing or logging everything, just check whether the memory usage is too high.
If not, continue the script execution. Otherwise, send yourself a notification email together with useful debugging information.
This simple procedure removes the need for you to actively check your scripts.
In fact, the scripts themselves will tell you when there’s something wrong 😉
Much better, isn’t it?
So, how can this be done in practice?
Let’s go back at the daemon example.
Now, before killing the script when the memory usage is too high, we send an email so that we know that this script has been terminated.
We also attach a file with the debug back trace and one with all the defined variables to make easier for us to debug the issue.
NOTE: you need to install PHPMailer first. Follow my PHPMailer tutorial to learn how to do it.
Here’s the code:
<?php
/* PHPMailer */
use \PHPMailer\PHPMailer\PHPMailer;
use \PHPMailer\PHPMailer\Exception;
require 'C:\xampp\htdocs\PHPMailer-master\src\Exception.php';
require 'C:\xampp\htdocs\PHPMailer-master\src\PHPMailer.php';
require 'C:\xampp\htdocs\PHPMailer-master\src\SMTP.php';
/* Remove the execution time limit */
set_time_limit(0);
/* Iteration interval in seconds */
$sleep_time = 1;
/* Memory limit (50Mb) */
$mem_limit = 52428800;
$array = array();
$iteration = 0;
while (TRUE)
{
$iteration++;
/* Memory check */
if (memory_get_usage(true) >= $mem_limit)
{
send_debug_email();
echo 'This PHP script has been killed for using too much memory. An email has been sent.';
die();
}
/* Sleep for the iteration interval */
sleep($sleep_time);
for ($i = 0; $i < 500000; $i++)
{
$array[] = $i;
}
}
function send_debug_email()
{
$mail = new PHPMailer(true);
try {
/* Source address */
$mail->setFrom('php@mysite');
/* Destination address */
$mail->addAddress('my_address@mysite');
/* Subject */
$mail->Subject = 'PHP script memory error';
/* Message */
$mail->Body = 'This PHP script has been killed for using too much memory.';
/* Add debug info as attachment */
$mail->addStringAttachment(print_r(debug_backtrace(), true), 'debug_backtrace.txt');
$mail->addStringAttachment(print_r(get_defined_vars(), true), 'defined_vars.txt');
/* Use SMTP. */
$mail->isSMTP();
/* SMTP server adrress. */
$mail->Host = 'mysmtp_server';
/* Use SMTP authentication. */
$mail->SMTPAuth = TRUE;
/* Set the encryption system. */
$mail->SMTPSecure = 'tls';
/* SMTP authentication username. */
$mail->Username = 'smtp@mysite';
/* SMTP authentication password. */
$mail->Password = 'smtp_passwd';
/* Set the SMTP port. */
$mail->Port = 587;
/* Send the mail. */
$mail->send();
}
catch (Exception $e)
{
echo $e->errorMessage();
}
catch (\Exception $e)
{
echo $e->getMessage();
}
}
A CAVEAT: RESOURCES
There is one problem with memory_get_usage() and memory_get_peak_usage():
they do NOT take resources into account.
PHP resource types include variables handled by external libraries or by the operating system, including:
- remote connections (HTTP, FTP…)
- XML files created with SimpleXML
- database connections
- …and more
The system memory for these types is not handled by the PHP core engine itself.
It’s the external library that does that.
Therefore, memory_get_[peak]_usage() does not include it in its result and you need to retrieve it in some other way.
This post from drib tech clearly explains this situation and also provides a solution:
Get the real amount of memory allocated by the PHP
The solution you find in the above post works on Linux systems only.
But don’t worry:
if you are using Windows, you can use the following code that relies on the tasklist windows tool:
<?php
/* Load a big XML file to see the memory usage difference */
$xml_file = 'C:\xampp\htdocs\big_xml_file.xml';
$xml = simplexml_load_file($xml_file);
if ($xml === false)
{
die('Unable to load and parse the XML file: "' . $xml_file . '"');
}
/* Tasklist command to get info about the process ID running this script */
$cmd = 'tasklist /fi "pid eq ' . strval(getmypid()) . '"';
/* Get the output from tasklist */
$tasklist = trim(exec($cmd, $output));
/* Parse the output to get the memory usage value */
$mem_val = mb_strrchr($tasklist, ' ', TRUE);
$mem_val = trim(mb_strrchr($mem_val, ' ', FALSE));
$mem_val = str_replace('.', '', $mem_val);
echo 'Memory usage from <em>memory_get_usage()</em>: ' . round(memory_get_usage(true) / 1024) . 'KB<br>';
echo 'Memory usage from <em>tasklist</em>: ' . $mem_val . 'KB<br>';
CONCLUSION
Now you know why it’s important to keep your scripts memory usage under control, and you know how to do it.
You learned the difference between memory_get_usage() and memory_get_peak_usage() and what the $real_usage argument really means.
You also saw how to include external resource types in the calculation, on both Linux and Windows systems.
Now I’m curious:
how much memory is the last PHP script you wrote using?
Go check it and tell me in the comments below!
If this tutorial has been helpful to you, please spend a second of your time to share it… thanks!
Alex
Hi Alex,
My script utilizes just 3-4MB but making 2 simultaneous requests would return error 504 Resource Limit even though the memory limit is set to 128MB.
Any help what could cause this or a walkaround?
Hello Richard,
Are you getting an 504 or 508 error? I’m asking because Resource Limit has the 508 code.
Anyway, there can be other issues other than memory, such as the execution time. On top of that, your hosting may enforce stricter memory limits then the ones set by PHP.
If you want, you can share the code using Pastebin and I’ll take a look. For a quicker reply you can also post it on my Facebook group: https://www.facebook.com/groups/289777711557686
If the real_usage argument is set to true the PHP DOCS say it will get the real size of memory allocated from system. If it’s false it will get the memory reported by emalloc()
Which one of these 2 options returns the max. memory allocated relative to the memory limit value in php.ini ?
I want to know how close was the script to hit that limit.
The description of the “memory_limit” parameter says:
“This sets the maximum amount of memory in bytes that a script is allowed to allocate.”
This suggests that the PHP limit is based on the *allocated* memory and not on just the used memory. Therefore, you need to set the real_usage parameter to TRUE to see how close to the limit it is.
sound is very good!!!!!! thanks for sharing
The below method could be help you:
function getVariableUsage($var) {
$total_memory = memory_get_usage();
$tmp = unserialize(serialize($var));
return memory_get_usage() – $total_memory;
}
$var = “Hey, what’s you doing?”;
echo getVariableUsage($var);
Thank you Parvez, interesting!
Thank you…
You are very welcome.
Hi Alex, I want to implement the email sending code in laravel since our website is getting too many request. I am confused where to put this php code, should I create a new middleware for this? sorry I am new to laravel.
Hi Alex could you add an example about checking the percentage of memory_limit that has been used? I think it’s useful for shared hosts.
Sure, I’ll update the tutorial as soon as possible.
Thanks for the suggestion 🙂
Hi T-900, I’ve just updated the loop and PHP daemon examples with the memory_limit percentage.
Let me know what you think.
Thanks it looks really nice, it’s been a while… 😉
BTW I was thinking that an important check to do could be to calculate available memory like as:
$available=min($free_ram,$memory_limit);
There are some situations where the available RAM can be less than memory_limit (for example multiple daemons running on a shared server).
I don’t know what overhead would be added by checking free RAM, though. But it’s still a possibility. Maybe only at start time to skip if there is low ram…
Also I was wondering if memory used by resources is computed in PHP’s own memory_limit enforcing and what memory_usage value is used (allocated or used) for that.
Ps. I use a Telegram Bot to send important log messages to myself instead of emails.
I’d love to read your opinions.
Hi (I’ll answer here to avoid too much nesting).
It may happen that the free system memory is less than the PHP memory limit, though such scenario would very much likely mean something’s wrong with the server itself (i.e., way too much load or memory leaks somewhere).
So yes, checking the free ram before running the script core can be a good idea if the server has a very low amount of RAM. The check should be done at the beginning of the script in run-once scripts, and at the beginning of every iteration in PHP daemons.
To answer your remaining questions:
– the RAM check itself has no significant overhead
– resources are not included into both memory_limit and memory_usage, but you can use some system tools to get their memory usage (see the post for the details)
Thanks again for your feedback!
You might want to correct your script…
Hi Jon, if you found an error I’ll be glad to fix my script. Could you please tell me what’s wrong?
You’re printing $mem_usage two times, it should be $mem_full_usage for the second echo command.
You’re right leo, the second echo should print $mem_full_usage indeed.
I fixed the code. Thanks!
Thanks Alex, your tutorials have been extremely helpful
Happy to help. Thank you for your feedback!