RSS Feed

7 tips to prevent PHP running out of memory

Is the following error familiar to you?

Fatal error: Allowed memory size of XXX bytes exhausted

It is to me and recently I’ve written an import script that reads the contents of 10 XML files. These files accumulate a total of 14.9MB in size. The XML files contain page content (A good 10,000), each page has references to images and PDFs which needed to be downloaded, stored on the filesystem in the same directory structure as well as imported into an asset manager, again in the same structure. Once the assets have been downloaded the script stores the contents of the XML files.

Poor programming could result in the script running out of memory rather quickly, there are a great deal of factors that could cause this – not just improper programming techniques but lack of knowledge in what affects memory. Because of this I’ve decided to write a few notes and tips on improving performance and memory usage.

Memory for PHP is cleared up my PHPs garbage collector. Sadly the garbage collector is a little lazy. In fact, it never seems to get to work on time and as a result memory is not freed quick enough for the scripts to progress. To work inline with the garbage collector here are a few tips on improving your code:


Tip 1 (Knowing what parts of your script is using the most memory)
If you’re looking to find out where your script is running out of memory the following function would be your best bet:

memory_get_peak_usage();

This function will return the current memory usage at the point it is executed. You’ll eventually see where your script is using the most amount of memory, or in my case, where the garbage collector decided it would rather go on lunch than do its job.


Tip 2 (Reassign null to vars along with un-setting them)

The unset(); function is useful when the garbage collector is doing its rounds however until then the unset(); function simply destroys the variable reference to the data, the data still exists in memory and PHP sees the memory as inuse despite no longer having a pointer to it. The solution: Assign null to your variables to clear the data, at least until the garbage collector gets ahold of it.

$var = null;

You can also use unset(); to unset the variable pointer, however there is little difference in memory usage, as far as I can see:

unset($var);


Tip 3 (__destruct your object references upon disposing of an object)

PHP does not release memory dedicated to an objects internal references to other objects until the garbage collector gets round to it. Because of this it’s worth adding a __destruct method to your objects which unsets all references to other objects. This can drastically help lower memory usage and is often ignored.

protected function __distruct()
{
  $this->childObject = null;
}


Tip 4 (Use functions where possible)

Upon the ending of an in use function PHP clears the memory it was using, at least more efficiently than if not using a function. If you are using recursive code or something similar that is memory intensive try putting the code into a function or method, upon closing of the function/method the memory used for the function will be garbaged much more efficiently than that of unsetting variables within the loop itself.


Tip 5 (Cache your filesystem checks, such as file_exists)

Checking if a file or directory exists before creating it, knowing a directory may be checked more than once? Using file_exists(); costs memory, not much, granted, but it does. The solution? Store the file paths you’ve already checked in an array (Or object property) and use in_array();

if(!in_array($path, $this->path_list))
{
  // ... Your code to deal with the file
}


Tip 6 (Database access is expensive)

Accessing a database is expensive, if you don’t have to, don’t. Based on tip 5, I am checking the filesystem despite being able to access the database to see if an asset exists. A lot more processing is required to access a database than there is checking the filesystem.


Tip 7 (Do not use objects if not needed)

Unless little or no performance difference I find it best to not using objects when obtaining data from a database, unless updating them. Objects add extra overhead for your scripts, as a result I tend to follow this rule of thumb:

- If not writing to a database, do not use objects, use arrays
- If you will be modifying data in a database, use objects – it tends to be cleaner and somewhat more efficient in the long run.


More tips?

Hopefully these tips will come in use for you. If you happen to have any tips you want to share feel free to post them here.

Posted in PHP on the 10th February 2010

15 people have spoken their minds!

  1. BaridBelMedar says:

    Great tips! There is a programmer at work struggling with some xml parsing that would have benefited from these… :)

  2. Pingback: Notable Tech Posts – 2010.02.21 | The Life of Lew Ayotte

  3. Phoenix says:

    I read about it some days ago in another blog and the main things that you mention here are very similar

  4. SAMANA says:

    You have tested it and writing form your personal experience or you find some information online?

  5. I happen to be reading your posts in the course of my smoke break, and I have to admit the whole article has been extremely educational and quite well written. I thought I would allow you realize that for some reason this website does not show well in IE eight. I wish Microsoft would stop upgrading stuff. We’ve a question for you personally. Would you thoughts swapping blog page roll links? That could be genuinely neat!

    • srcnix says:

      Thanks for the heads up. This theme is actually borrowed while I have a design worked on.

      If you’d like to share links please email me using the available contact form on this site.

      Thanks again.

  6. Useful article do you mind if i summerize this on my blog? Thanks

  7. Xavier C says:

    In the part where you have
    if(!in_array($path, $this->path_list))
    It is a bit more efficient if you use isset() instead. So just save the paths of the files as keys of the array, and do
    if(!isset($path[$this->path_list]))
    The value can be either a bool or just the path itself if you need it for some reason

  8. Sergio Ruiz says:

    Thanks for the tips ;) it has been useful to solve some doubts, I have, and put ideas in place!

SPEAK YOUR MIND...

Your email address will not be published. Required fields are marked *

*