Sunday, March 20, 2011

Dynamically Adjusting PHP Memory Limit During Runtime

Abstract

At PHP runtime, processes would typically require a variable size memory requirement based on data input and how the process manipulates the input. For a very predictable amount of input and resulting data, a fixed limit would often suffice. But what if you would encounter frequent and intermittent spikes from your predicted memory requirement? You would probably want the memory limit adjusted dynamically during the process runtime.

PHP has a static declaration of its memory limit per process. The default prior to PHP 5.2 was 8M and 16M all throughout 5.2. Now at 5.3 the default is 128M.This memory limit is the amount of memory that it could use in the duration of its runtime unless changed. In a per script basis, a developer can change the limit using ini_set function (i.e ini_set('memory_limit', '256M') ). You can write a function or method to frequently check for memory usage and use ini_set to adjust memory limit accordingly. However, you wouldn't want your code littered with some sort of check logic unnecessarily, hence the need for a better way of doing it.

Theory of Operation

Using PHP's declare construct, we can use the tick directive to call upon a handler function to adjust the memory of your running process / script dynamically without the hassle of littering code your code with such check logic. See below for a reference implementation. It's working but experimental as I haven't fully tested it for production use. On a side note, other than what is presented, the same implementation opens the door for event-driven software architecture in PHP programming.
Here's the code. Enjoy!
<?php
declare(ticks=5);
function tick_handler()
{
        $cur = memory_get_usage();
        $val = ini_get('memory_limit');
        $last = strtolower($val[strlen($val)-1]);
        switch($last) {
                // The 'G' modifier is available since PHP 5.1.0
                case 'g':
                    $val = substr($val,0,(strlen($val)-1));
                    $val *= 1024 * 1024 * 1024;
                    break;
                case 'm':
                    $val = substr($val,0,(strlen($val)-1));
                    $val *= 1024 * 1024;
                    break;
                case 'k':
                    $val = substr($val,0,(strlen($val)-1));
                    $val *= 1024;
        }
        $delta = (($val - $cur) / $val) * 100;
        $threshold = 98; //percent threshold before adding more memory;
        if ($delta < $threshold) {
                $inc = bcmul($val,0.2); //add 20% more than the original memory limit
                $tot = $inc + $val;
                ini_set('memory_limit', (int) $tot);
                echo "\n memory limit adjusted dynamically - $tot";
                sleep(1);
        }

}

register_tick_function('tick_handler');
$a = "";
for ($i = 0; $i < 10000000000000000; $i++){
        $a .= $i;
//        echo "\n" . memory_get_usage();
}
  • Related Links Widget for Blogspot

No comments: