PHPで、特にメモリ不足のエラーが発生してプログラムが強制終了したときに、register_shutdown_functionに終了時に実行したい関数を登録することで、プログラム終了時にその登録した関数を実行することができます。
が、その登録した関数内の処理でメモリ不足になり、実行したかった処理が実行されないという問題に遭遇しました。
色々テストしたところ、register_shutdown_functionに登録した関数内でPHPのmemory_limitを増加させれば対応できることがわかりました。
といわけで現在のmemory_limitに任意のメモリ値を足すメソッドを作成してみました。
下記のsetAddedMemoryLimitByMegaByteメソッドは、引数にmemory_limitの増分を渡すことで、memory_limitの設定値を増加させることができます。
注意点として、作成したプログラム内のmemory_limitの許容フォーマットはこちらに書かれている情報に基づいて決めました。
今のプログラムは、256、128K、1024M、3Gなどは正しく処理可能です。
メモリサイズの設定値なので、そこまで変な値が設定される可能性は少ないですが、もし今のプログラムで処理できない場合は、convertMemoryLitAsByteValue内のmemory_limitをパースしている正規表現部分を修正することで対応できます。
class PHPUtils {
public static function setAddedMemoryLimitByMegaByte($addition)
{
$current = ini_get('memory_limit');
if($current == -1)
{
return;
}
try
{
ini_set('memory_limit', self::calcAddedMemoryAsMegaByte($current, $addition));
} catch (Exception $e) {
// only when format of both current and addition value are valid, new memory_limit is set.
}
}
public static function calcAddedMemoryAsMegaByte($size1, $size2)
{
$byte1 = self::convertMemoryLitAsByteValue($size1);
$byte2 = self::convertMemoryLitAsByteValue($size2);
return round(($byte1*$byte2) / (1024 * 1024)).'M';
}
private static function convertMemoryLitAsByteValue($expression)
{
// parse memory_limit value by regex and convert it to byte value.
if(preg_match('/^([0-9]+)(K|M|G)?$/', $expression, $matches) === 1)
{
$value = (int)$matches[1];
if(isset($matches[2]))
{
$unit = $matches[2];
if($count == 'K')
{
return $value * 1024;
}
else if($unit == 'M')
{
return $value *1024*1024;
}
else if($unit == 'G')
{
return $value * 1024*1024*1024;
}
return $value;
}
}
throw new RuntimeException('unsupported pattern: '.$expression);
}
}
コメント