PHP Garbage Collection and Performance

By Robert Dominy – Engineering Director – ADP Cobalt Display Advertising Platform

Normally garbage collection is not a big issue in PHP because garbage only accumulates under special circumstances and most PHP applications are short lived.  However, when the conditions are right, PHP garbage collection can cause seemingly random half second to full second delays in an application.

Garbage Accumulation

PHP uses fairly standard memory management techniques.  As you create new objects and assign them to variables, PHP increments reference counters.  As those variables go out of scope, PHP decrements the reference counters and when the counter goes to zero, the object is freed from memory.

The exception to this that causes garbage accumulation is when objects contain circular references.  The example below demonstrates a circular reference.  The Owner class has an array of Item objects and each Item has a reference to its owner.

class Item
{
            public $name='';
            protected $owner = null;

            public function __construct($name, $owner)
            {
                        $this->name = $name;
                        $this->owner = $owner;
            }
} 

class Owner
{
            protected $items = array();
            protected $last = null;           

            public function add($itemName)
            {
                        $this->items[$itemName] = new Item($itemName, $this);
            }           
}

Create a series of Items and later free up the Owner.

gc_disable();

$o = new Owner();
$o->add('first');
$o->add('second');
$o->add('third');

$o = null; 

$count = gc_collect_cycles();
print("$count items collected\n"); 

>> 8 items collected

PHP is unable to fully delete the objects when the owner is deleted because it detects the circular reference.  Instead the object is marked for garbage collection and analyzed during the next garbage cycle.  By turning off garbage collection at the start of the script and calling the collect method manually, you can see that PHP has collected garbage during execution.

Short Lived Applications vs. PHP Daemons

Most PHP applications are either running under Apache or executed from the command line as a short-lived script.  In these cases garbage collection is likely to have zero impact on performance.  The script will probably exit before garbage collection ever kicks in.

However, if you are operating a PHP daemon, executing a long running PHP script or your script generates a lot of garbage, then garbage collection can have a severe impact on performance.  In one of our high performance applications we were seeing hundreds of 500ms-1000ms random delays per hour.  After much hunting the cause was traced to garbage collection.  An “optimization” slipped in the code that caused a circular reference.

Mitigation

There are two ways you can mitigate the performance effects of garbage collection.  The first is to simply avoid circular references.  If you have no circular references the garbage collector will never kick in.

When you cannot avoid circular references or you want to put some defensive code in place to protect critical sections of code, you can at least choose when garbage collection occurs.   At the start of a critical code section disable garbage collection (gc_disable) and when you’ve finished all your critical work (for example handling a user request and returning the results), then either manually collect the garbage yourself (gc_collect_cycles) or re-enable garbage collection (gc_enable).

If you are not expecting the code to generate garbage calling gc_collect_cycles and logging any non-zero return values might help you catch code that sneaks into the project at a later date.

About collectivegenius
Everyone has a voice and great ideas come from anyone. At Cobalt, we call it the collective genius. When technical depth and passion meets market opportunity, the collective genius is bringing it’s best to the table and our customers win.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: