致命的なエラー:134217728バイトの許容メモリサイズが使い果たされました(CodeIgniter + XML-RPC)


618

私は、新しい売上データを1つの集中データベースに定期的に送信するクライアントPOSシステムを多数持っています。このデータベースは、データを1つの大きなデータベースに格納してレポートを生成します。

クライアントPOSはPHPPOSに基づいており、標準のXML-RPCライブラリを使用して販売データをサービスに送信するモジュールを実装しました。サーバーシステムはCodeIgniterに基づいて構築され、WebサービスコンポーネントにXML-RPCおよびXML-RPCSライブラリを使用します。大量の販売データ(salesテーブルからの50行程度、およびsales内の各アイテムに関連するsales_itemsからの個々の行)を送信するたびに、次のエラーが発生します。

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)

のデフォルト値は128Mですが、php.iniこれは大きな問題であると思います。実際、この値を1024Mに設定してみましたが、エラーが発生するまでに時間がかかります。

私が取った手順については、サーバー側のすべての処理を無効にして、入力に関係なく定型応答を返すようにそれを仕掛けました。ただし、問題は実際のデータ送信にあると思います。PHPの最大スクリプト実行時間を無効にしてみましたが、それでもエラーが発生します。


5
私は少し混乱しています...エラーはどこで発生しますか-クライアントまたはサーバーで?そして、どの段階で...クライアント送信、サーバー受信、サーバー処理、サーバー送信、クライアント受信、またはクライアント処理?
グレッグ、

2
エラーは、クライアントの送信中またはサーバーの受信中に発生するようです。私はすべてのサーバーサイド処理を無効にし、送信されたデータに関係なく、それをリギングして返信定型文を送信しようとしました。特定の量のデータを送信するとエラーが発生します。PHP.ini設定を変更しています。
ArcticZero、2009

42
メモリの制限は128MBです、それを解決してください:ini_set('memory_limit', '256M');

9
要約では、「リークを無視するだけ」の回答、CodeIgniterをDrupalと混同した人々、およびポイントを獲得するために他の人々の回答をコピーして貼り付けた人々に反対票を投じました。これの答えの質はひどいです。
Matti Virkkunen

回答:


697

memory_limitbyの変更は適切な解決策でini_set('memory_limit', '-1');はありません。しないでください。

PHPコードのどこかにメモリリークがあり、サーバーに必要なメモリをすべて使用するように指示しています。あなたはまったく問題を修正しなかったでしょう。サーバーを監視すると、おそらくほとんどのRAMを使い果たし、ディスクにスワップしていることがわかります。

コード内の問題のあるコードを追跡して修正することをお勧めします。


174
@ジェフあなたはおそらく95%の確率で正しいです。ただし、実際にはさらに多くのメモリが必要な場合があります。たとえば、アプリが大量のデータをメモリに読み込んで処理しているとします(たとえば、15,000個のコンポーネントを持つ部品表)。コードにバグがあるとは限りません。メモリが少しだけ必要な場合もあります(128Mではなく256Mなど)。ただし、-1に設定することは恐ろしく悪いことであることに同意します。しかし、実行時に合理的な状況に合わせてメモリ制限を調整することは、完全に許容できる私見です。
パイライト2014年

24
@pyriteはい、あなたは時々 、プロセスがより多くのメモリを必要とすることが正しいですが、あなたが言ったか、512メガバイト、なぜいないではないとして、あなたは、256メガバイトのようないくつかの論理的な量にメモリ制限を増やす必要が-1;)
ルーカス・Lukac

9
@jeff私は完全に同意します。値は、テスト目的の開発環境でのみ-1役立つ可能性があります。
Esolitos 2015

4
残りの5%に名前を付けた場合の@Pyriteは、データをチャンクで読み取り、より多くのメモリを使用する代わりにワーカーを使用してデータを処理します。このソリューションは、データが増大した場合に時間をかけてサーバーにメモリをどんどん詰め込んでおくことを除いて、提案が機能しない間も拡張できます。
バーズム2015

2
最も一般的な方法では、ORMでこの問題は、phpのメモリ制限よりも多くのfetchAllデータを取得しようとしたときに発生します。たとえば、月次レポートを生成しようとした場合。
Stepchik

213

ini_set('memory_limit', '-1');デフォルトのPHPメモリ制限を上書きします。


16
@williamcarswell; このコンテキストで-1は、PHPが無制限と理解している値です。
Alix Axel

7
@ArseniuszŁozicki-サーバー節約できないリソースも消費します。
ケンウィリアムズ

124
これが非常に多くの賛成票を獲得するのは残念です。php.iniの編集またはini_setを使用して正確な値に設定することは、より多くのメモリが必要な場合に完全に有効なソリューションです。無制限に設定するのは危険なハックです:(
Jeff Davis

24
次に@ user1767586を適切な値に設定します。1024Mに設定することで、スクリプトがエラーをスローしないようにすることができます。この答えがini_set( 'memory_limit'、 '1024M');と言った場合; あなたはそれをコピーして貼り付けても大丈夫です。これを-1に設定すると、すべてのメモリを消費するスクリプトを使用するように設定されます。特にこれを日常的に行う場合。「危険」を引用符で囲んでも、それほど危険ではありません。あなたは本当にあなたのホストサーバーをホースにすることができます。多分データを破壊し始めます。わからない、たぶんあなたの仕事を失うの?私にはかなり危険に聞こえます。:|
ジェフデイビス

3
+161票と-3票の答えが同じであることを確認すると悲しい:(
akarthik10

130

正しい方法は、php.iniファイルを編集することです。memory_limitご希望の値に編集します。

あなたの質問から、128M(これはデフォルトの制限です)を超えています。そのため、それほど多くのことをするべきではないため、コードに深刻な問題があります。

なぜそんなにかかるのかを知っていて、それmemory_limit = 512M以上の設定を許可したいなら、あなたは良いはずです。


7
正直なところ、深刻な量のデータをキャッシュする場合、これが正しい答えです。128Mは特定のスクリプトには十分ではありません。多くの場合、512Mまたは1024Mで十分ですが、ケースバイケースで決定する必要があります。
ジェフデイビス

2
ただし、ユーザー数が増える場合は、メモリの大量使用を避けてください
Basav

2
memory_limit = -1; php.iniで設定

2
@YumYumYumこれは、他の方法でメモリ使用量を監視している場合にのみ必要なmemory_limitを削除します。なんらかの時点でメモリが大量に使用されている場合、OSはプロセスを強制終了します。
Flimm

したがって、多くのメモリを使用するスクリプトを実行しているが、一度だけ実行する必要がある場合は、実行時にプロセスのメモリ制限を増やして、1回限りのメモリ制限を再度下げることができます。スクリプトが実行されますか?
chromechris

95

PHPのメモリ割り当ては、永続的または一時的に調整できます。

永久に

PHPのメモリ割り当ては、2つの方法で永続的に変更できます。

php.iniファイルにアクセスできる場合は、の値をmemory_limit希望の値に編集できます。

php.iniファイルへのアクセス権がない場合(およびWebホストで許可されている場合)、.htaccessファイルを介してメモリ割り当てを上書きできます。追加しphp_value memory_limit 128Mます(または必要な割り当てが何であれ)。

一時的

PHPファイル内からその場でメモリ割り当てを調整できます。あなたは単にコードini_set('memory_limit', '128M');(またはあなたが望むどんな割り当てでも)を持っています。値を「-1」に設定することで、メモリ制限を削除できます(ただし、マシンまたはインスタンスの制限は適用される場合があります)。


2
ありがとうphp.iniを上書きしている.htaccessに値が設定されているかどうかを確認するつもりはなかったので、なぜ+1
HostMyBus

61

特にORMなどの抽象化を使用する場合、PHPスクリプトでメモリリークを取得するのは非常に簡単です。Xdebugを使用してスクリプトのプロファイルを作成し、そのすべてのメモリがどこに移動したかを確認してください。


1
Xdebugを試してみます。今まで使ったことがないので、読んでおく必要があります。返信ありがとうございます!私がこれに対する答えをすぐに見つけられることを願っています...
ArcticZero

34
PHPはメモリの管理に参照カウントを使用することに注意してください。したがって、循環参照またはグローバル変数がある場合、それらのオブジェクトはリサイクルされません。これは通常、PHPのメモリリークの原因です。
troelskn

Xdebugは、CIのXmlrpc.phpライブラリが私のメモリリークの原因であることを示しています。万が一、CodeIgniterのXML-RPCライブラリに知っておくべき問題はありますか?サーバー側の処理をすべて無効にしてみましたが、十分なデータを供給した場合でもメモリが不足します。
ArcticZero、2009

1
CIがわからない/使用していないため、わかりません。ただし、おそらく使用後に解放されないオブジェクトを見つけるようにしてください。おそらく循環参照が原因です。それは探偵です。
troelskn 2009

1
これが実際に問題に対処することをアドバイスする唯一の回答です。もう1つの答えは、症状に包帯をし、病気を無視するために記憶を刺激します。
クリスベイカー

56

2250万レコードをarray_pushを使用して配列に追加する4Gと、php.iniファイルのメモリ制限として使用すると、約2000万レコードで「メモリ不足」の致命的なエラーが発生し続けました。これを修正するために、私はステートメントを追加しました

$old = ini_set('memory_limit', '8192M');

ファイルの先頭。今、すべてが正常に動作しています。PHPにメモリリークがあるかどうかはわかりません。それは私の仕事ではなく、気にしません。私は自分の仕事を成し遂げる必要があるだけで、これはうまくいきました。

プログラムは非常に簡単です:

$fh = fopen($myfile);
while (!feof($fh)) {
    array_push($file, stripslashes(fgets($fh)));
}
fclose($fh);

致命的なエラーは、メモリ制限を引き上げてエラーを解消するまで、3行目を指しています。


10
つまりini_set('memory_limit', '8192M');
Gogol

2
スクリプトをそのようなもののために最適化する時間があるとしたら、なんて贅沢でしょう。または、ETLツールなどを調査して比較および学習します。現実の世界では、メモリの許容量を大幅に増やし、実行し、次に進みます。
Matthew Poer

45

memory_limitset in でもこのエラーが発生し続けphp.ini、値が正しく読み取られましたphpinfo()

これから変更することにより:

memory_limit=4G

これに:

memory_limit=4096M

これにより、PHP 7の問題が修正されました。


23

上記のエラーが表示された場合-特に(tried to allocate __ bytes)が低い値である場合、それは無限ループを示している可能性があります。

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

これらの2行を有効にした後、それは働き始めました:

; Determines the size of the realpath cache to be used by PHP. This value should
; be increased on systems where PHP opens many files to reflect the quantity of
; the file operations performed.
; http://php.net/realpath-cache-size
realpath_cache_size = 16k

; Duration of time, in seconds for which to cache realpath information for a given
; file or directory. For systems with rarely changing files, consider increasing this
; value.
; http://php.net/realpath-cache-ttl
realpath_cache_ttl = 120


19

memory_limitfastcgi / fpmを変更することで、これを適切に修正できます。

$vim /etc/php5/fpm/php.ini

メモリを128から512に変更します。以下を参照してください

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 128M

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 512M

18

サイトのルートディレクトリ:

ini_set('memory_limit', '1024M');

1
これでうまくいきました。ワンラインソリューションが大好きです。+1で簡単
スティーブC

14

php.iniファイルのメモリ制限を変更し、Apacheを再起動します。再起動後、phpinfo();を実行します。memory_limit変更確認のための任意のPHPファイルからの関数。

memory_limit = -1

メモリ制限-1は、メモリ制限が設定されていないことを意味します。現在は最大です。


13

Drupalユーザーの場合、このChris Laneの回答:

ini_set('memory_limit', '-1');

動作しますが、オープニングの直後に配置する必要があります

<?php

サイトのルートディレクトリにあるindex.phpファイルのタグ。


13

Drupal 7では、sites / defaultフォルダーにあるsettings.phpファイルでメモリ制限を変更できます。260行目あたりに、次のように表示されます。

ini_set('memory_limit', '128M');

php.ini設定が十分に高い場合でも、Drupalのsettings.phpファイルで設定されていない場合、128 MBを超える容量を消費することはできません。


1
Drupal7では、settings.phpにそのようなコードの文字列はありません
FLY

drupal 6のsettings.phpにも文字列はありません
AllisonC

12

ファイルのmemory_limit値を変更するのではなくphp.ini、大量のメモリを使用する可能性があるコードの一部がある場合は、memory_limitそのセクションを実行する前にbeforeを削除し、その後で置き換えることができます。

$limit = ini_get('memory_limit');
ini_set('memory_limit', -1);
// ... do heavy stuff
ini_set('memory_limit', $limit);

7

PHP 5.3以降.user.iniでは、public_htmlフォルダーにファイルを配置することでメモリ制限を変更できます。上記のファイルを作成し、次の行を入力するだけです。

memory_limit = 64M

一部のcPanelホストはこのメソッドのみを受け入れます。


7

クラッシュページ?

ここに画像の説明を入力してください

(MySQLが大きな行をクエリする必要がある場合に発生します。デフォルトでmemory_limitは、ハードウェアにとってより安全な小さな値に設定されています。)

増加する前に、システムの既存のメモリステータスを確認できますphp.ini

# free -m
             total       used       free     shared    buffers     cached
Mem:         64457      63791        666          0       1118      18273
-/+ buffers/cache:      44398      20058
Swap:         1021          0       1021

ここでは、次のように値を増やしてservice httpd restartから、クラッシュページの問題を修正しています。

# grep memory_limit /etc/php.ini
memory_limit = 512M

free -m新しいmemory_limitを決定するためにコマンドを実行した後、どの番号(行と列?)を見る必要がありますか?
kiradotee

7

ini_set('memory_limit', '-1');Webページの上部に行を追加するだけです。

そして、必要に応じて-1からの代わりにメモリを設定できます16M


6
これは多くの既存の答えと同じことを言っているようです。新しい資料が新しいものを提供する場合にのみ、人気のある質問に回答を追加するのが最善です。
ハーフタイム

6

いったいこの小さな関数がメモリリークを引き起こす理由を突き止めるために頭を悩ましている人にとって、時には小さな間違いによって、関数が永遠にそれ自体を再帰的に呼び出し始めます。

たとえば、プロキシするオブジェクトの関数に同じ名前を持つプロキシクラス。

class Proxy {

    private $actualObject;

    public function doSomething() {

        return $this->actualObjec->doSomething();
    }
}

その小さなactualObjecメンバーを持っていくことを忘れることがあるかもしれません。プロキシには実際にそのdoSomethingメソッドがあるため、PHPはエラーを出さず、大きなクラスの場合、それを数分間目に見えないようにして、その理由を見つけることができます。メモリをリークしています。


そして別のヒント:die('here')コードを入力してそのステートメントを移動し、再帰がどこから始まるかを確認できます。
toddmo

6

以前に機能していたよりも小さいデータセットで実行しているときに、以下のエラーが発生しました。

致命的なエラー:173行目のC:\ workspace \ image_management.phpで許可されたメモリサイズ134217728バイトを使い果たしました(4096バイトを割り当てようとしました)

障害の検索でここに来たので、以前の回答では必ずしも技術的な解決策ではなく、もっと単純なものだと思います。私の場合、それはFirefoxでした。プログラムを実行する前は、すでに1,157 MBを使用していました。

私は50分のビデオを何日も一度に少しずつ見ていましたが、それは混乱を招きました。それは専門家が考えずに修正する一種の修正ですが、私のようなものにとっては心に留めておく価値があります。


今日もGoogle Chromeで同様のことがありました。私はこの答えに非常に懐疑的でした...しかし、シークレットウィンドウを開いて同じスクリプトをもう一度実行すると、バイトの枯渇が解消したことが明らかになりました。研究は続いています。
mickmackusa

2

次のようなスクリプトを実行します(たとえば、cronの場合): php5 /pathToScript/info.php、同じエラーが発生します。

正しい方法: php5 -cli /pathToScript/info.php


2

WHM搭載のVPS(仮想プライベートサーバー)を実行している場合、PHP.INIを直接編集する権限がない可能性があります。システムが実行する必要があります。WHMホストのコントロールパネルで、[ サービスの構成] →[ PHP構成エディター ]に移動して、次のように変更しmemory_limitます。

WHM 11.48.4でのmemory_limitの更新


2

含める場合や必要_dbconnection.php_とする場合に役立ちます。_functions.phpヘッダーに含めるのではなく、実際に処理されるファイル。それ自体に含まれています。

したがって、ヘッダーフッターが含まれている場合は、ヘッダーが含まれる前にすべての機能ファイルを含めてください。


2

を使用yieldすることも解決策になるかもしれません。ジェネレータ構文を参照してください。

PHP.iniより大きなメモリストレージ用にファイルを変更する代わりにyield、ループ内に実装することで問題が解決する場合があります。収量は、すべてのデータを一度にダンプするのではなく、1つずつ読み取って、メモリ使用量を大幅に節約します。


2
PHP.ini?ですphp.iniよね?
Peter Mortensen

1

このエラーは、例外処理やその他の操作を含む再帰を引き起こすPHPコードのバグが原因で発生する場合があります。残念ながら、小さな例を作成することはできませんでした。

何度か私に起こったこれらのケースでは、 set_time_limitが失敗し、ブラウザは無限ループまたはこの質問のトピックである致命的なエラーメッセージのいずれかでPHP出力をロードしようとし続けます。

追加して、許可される割り当てサイズを減らす

ini_set('memory_limit','1M');

コードの最初の方で、致命的なエラーを防ぐことができるはずです。

次に、終了するプログラムが残っている可能性がありますが、デバッグは依然として困難です。

この時点でBreakLoop()、プログラム内に呼び出しを挿入して制御を取得し、プログラムのどのループまたは再帰が問題の原因であるかを調べます。

BreakLoopの定義は次のとおりです。

function BreakLoop($MaxRepetitions=500,$LoopSite="unspecified")
    {
    static $Sites=[];
    if (!@$Sites[$LoopSite] || !$MaxRepetitions)
        $Sites[$LoopSite]=['n'=>0, 'if'=>0];
    if (!$MaxRepetitions)
        return;
    if (++$Sites[$LoopSite]['n'] >= $MaxRepetitions)
        {
        $S=debug_backtrace(); // array_reverse
        $info=$S[0];
        $File=$info['file'];
        $Line=$info['line'];
        exit("*** Loop for site $LoopSite was interrupted after $MaxRepetitions repetitions. In file $File at line $Line.");
        }
    } // BreakLoop

$ LoopSite引数は、コード内の関数の名前にすることができます。表示されるエラーメッセージは、BreakLoop()呼び出しを含む行を示しているため、実際には必要ありません。


-1

私の場合、関数の記述方法に関する簡単な問題でした。メモリリークは、関数の入力変数に新しい値を割り当てると発生します。例:

/**
* Memory leak function that illustrates unintentional bad code
* @param $variable - input function that will be assigned a new value
* @return null
**/
function doSomehting($variable){
    $variable = 'set value';
    // Or
    $variable .= 'set value';
}

-6

コードから次の行を削除すると、すべて正常に機能しました。

set_include_path(get_include_path() . get_include_path() . '/phpseclib');
include_once('Net/SSH2.php');
include_once('Net/SFTP.php');

これらの行は、実行中のすべてのファイルに含まれていました。ファイルを1つずつ実行すると、すべてが正常に機能しましたが、すべてのファイルを一緒に実行すると、メモリリークの問題が発生しました。どういうわけか「include_once」は一度も含まれていません、または私は何か間違っています...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); これにより、行のあるファイルごとにパス「/ phpseclib」が1回追加されます。そのため、何度も追加できます。設定ファイルと設定ファイルに入れることをお勧めしinclude_onceます。
Farfromunique 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.