私は定期的に新しい販売データを1つの集中型データベースに送信する多数のPOSシステムを持っています。
クライアントPOSはPHPPOSをベースにしており、私は販売データをサービスに送信するために標準のXML-RPCライブラリを使用するモジュールを実装しました。サーバーシステムはCodeIgniter上に構築されており、WebサービスコンポーネントにXML-RPCおよびXML-RPCSライブラリを使用します。大量の販売データ(salesテーブルから50行、sales_itemsから販売内の各商品に関連する行)を送信するたびに、次のエラーが発生します。
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)
128Mはphp.ini
のデフォルト値ですが、私はそれが破るべき巨大な数であると思います。実際、私はこの値を1024Mに設定しようとさえしました、そしてそれがするすべてはエラーを出すのにより長い時間がかかることです。
私が取ったステップに関しては、私はサーバー側のすべての処理を無効にしようとしました、そしてそれは入力に関係なく缶詰の応答を返すようにそれを装備しました。しかし、問題は実際のデータ送信にあると思います。私はPHPの最大スクリプト実行時間を無効にしようとさえしましたが、それでもエラーになります。
ini_set('memory_limit', '-1');
によるmemory_limit
の変更は not 適切な解決策です。しないでください。
あなたのPHPコードはどこかにメモリリークがあるかもしれません、そしてあなたはそれが望むすべてのメモリを使うようにサーバに言っています。あなたはまったく問題を解決しなかったでしょう。サーバーを監視している場合は、おそらくRAMの大部分を使い果たし、さらにはディスクにスワップしていることがわかります。
あなたはおそらくあなたのコードの中の問題のあるコードを突き止めてそれを修正しようとするべきです。
ini_set('memory_limit', '-1');
はデフォルトの PHPメモリ制限 を上書きします。
正しい方法はあなたのphp.ini
ファイルを編集することです。 memory_limit
をあなたの望む値に編集してください。
あなたの質問からして、128M
(これはデフォルトの制限です)を超えています。それほど多くはかかりませんので、あなたのコードには重大な問題があります。
なぜそれがそんなにかかるのかを知っていて、memory_limit = 512M
以上に設定したいのなら、あなたは良いはずです。
PHPのメモリ割り当ては、恒久的または一時的に調整できます。
PHPメモリの割り当ては、2通りの方法で恒久的に変更できます。
php.ini
ファイルにアクセスできる場合は、memory_limit
の値を希望の値に編集できます。
あなたがあなたのphp.ini
ファイルにアクセスできない(そしてあなたのウェブホストがそれを許可する)場合、あなたはあなたの.htaccess
ファイルを通してメモリ割り当てを上書きすることができます。 php_value memory_limit 128M
を追加します(または、あなたが望む割り当てであれば何でも)。
PHPファイル内からメモリ割り当てをその場で調整できます。あなたは単にini_set('memory_limit', '128M');
というコードを持っています。値を "-1"に設定すると、メモリ制限を削除できます(ただし、マシン制限またはインスタンス制限は適用される場合があります)。
PHPスクリプトでメモリリークが発生するのは非常に簡単です。特にORMなどの抽象化を使用する場合は特にそうです。 Xdebugを使用してスクリプトをプロファイルし、そのメモリがどこにいったのかを調べてください。
Array_Pushを使って2250万レコードを配列に追加したとき、php.iniのメモリ制限として4Gを使用して、約20Mレコードで "メモリを使い果たした"致命的なエラーが発生し続けました。これを修正するために、私は文を追加しました
$old = ini_set('memory_limit', '8192M');
ファイルの先頭にあります。今、すべてがうまくいっています。私はphpにメモリリークがあるかどうか、それが私の仕事ではないかどうかも知りませんし、気にしません。仕事を終わらせるだけでいいのです。
プログラムはとても簡単です。
$fh = fopen($myfile);
while (!feof($fh)) {
array_Push($file, stripslashes(fgets($fh)));
}
fclose($fh);
致命的なエラーは、iがメモリ制限を引き上げるまで3行目を指しています。
memory_limit
にphp.ini
を設定し、phpinfo()
を使用して値を正しく読み取っても、このエラーが発生し続けました。
これを変更することで:
memory_limit=4G
これに:
memory_limit=4096M
これはPHP 7の問題を修正しました。
上記のエラーが表示されたとき - 特に(tried to allocate __ bytes)
が低い値の場合、それは、逃げることなく自分自身を呼び出す関数のように、無限ループの指標となる可能性があります。
function exhaustYourBytes()
{
return exhaustYourBytes();
}
これら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
Fastcgi/fpmのmemory_limitを変更することでこれを正しく修正できます。
$vim /etc/php5/fpm/php.ini
128から512のようにメモリを変更してください下記参照
; Maximum amount of memory a script may consume (128MB)
; http://php.net/memory-limit
memory_limit = 128M
に
; Maximum amount of memory a script may consume (128MB)
; http://php.net/memory-limit
memory_limit = 512M
あなたのサイトのルートディレクトリ: -
ini_set('memory_limit', '1024M');
memory_limit
ファイルのphp.ini
値を変更するのではなく、大量のメモリを使用する可能性があるコード部分がある場合は、そのセクションを実行する前にmemory_limit
を削除してから置き換えます。
$limit = ini_get('memory_limit');
ini_set('memory_limit', -1);
// ... do heavy stuff
ini_set('memory_limit', $limit);
Drupalの7では、あなたはあなたのサイト/既定のフォルダにあるのsettings.phpファイルにメモリ制限を変更することができます。ライン260の周りに、あなたはこれを参照してくださいよ。
ini_set('memory_limit', '128M');
あなたのphp.iniの設定が十分に高い場合であっても、これはあなたのDrupalのsettings.phpファイルに設定されていない場合は、128メガバイト以上を消費することはできません。
Drupalユーザーにとって、このChris Laneの答えは:
ini_set('memory_limit', '-1');
動作しますが、開始直後に配置する必要があります
<?php
サイトのルートディレクトリにあるindex.phpファイルにタグを付けます。
メモリ制限を php.ini fileから変更してApacheを再起動します。再起動後、 phpinfo()を実行してください。 memory_limit変更確認のための任意のphpファイルからの関数。
memory_limit = -1
メモリ制限-1は、現在メモリ制限が設定されていないことを意味します。
PHP 5.3以降では、.user.ini
ファイルをpublic_html
フォルダーに置くことでメモリー制限を変更できます。上記のファイルを作成して、その中に次の行を入力するだけです。
memory_limit = 64M
一部のcPanelホストはこのメソッドのみを受け入れます。
地球上でこの小さな関数がなぜメモリリークを引き起こすのかを調べるために自分の髪の毛を傷つけている人のために、時々ちょっとした間違いで、関数は永遠にそれ自身を再帰的に呼び出し始めます。
例えば、それを代行しようとしているオブジェクトの機能と同じ名前を持つProxy Class。
class Proxy {
private $actualObject;
public function doSomething() {
return $this->actualObjec->doSomething();
}
}
実際には、その少しactualObjecメンバーを持ってくるのを忘れるかもしれません、そして、Proxyが実際にそのdoSomethingメソッドを持っているので、PHPはあなたにエラーを与えないでしょう。なぜそれがメモリをリークしているのかを調べるために数分のうちに。
(MySQLが大きな行をクエリしなければならないときに起こります。デフォルトではmomory_limitはsmallに設定されています。これはハードウェアにとって安全でした)
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
以前の作業よりも小さいデータセットを実行しているときに、以下のエラーが発生しました。
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes) in C:\\workspace\image_management.php on line 173
障害の検索がここに私をもたらしたので私はそれが常に上記の技術的な解決策ではなく、もっと単純なものであることに言及したいと思いました。私の場合はFirefoxでした。プログラムを実行する前は、すでに1,157 Mを使用していました。
私が数日の間に一度に少しずつ50分のビデオを見ていたことがわかり、それが物を台無しにしました。それは熟考することさえもせずに専門家が修正するような種類の修正ですが、私のような人にとっては注意する必要があります。
WHM搭載のVPS(Virtual Private Server)を使用している場合は、PHP.INIを直接編集する権限がないことがわかります。システムはそれをしなければならない。 WHM Hostコントロールパネルで、Service Configuration> PHP Configuration Editorに移動し、memory_limitを変更します。
このようにスクリプトを実行すると(例えばcronの場合)、php5 /pathToScript/info.php
と同じエラーが発生します。
正しい方法はphp5 -cli /pathToScript/info.php
次のものを含めるときや必要とするときに便利です。
dbconnection.php 、実際に処理されるファイル内の_functions.php
ヘッダーに含めるのではなくそれ自体が含まれています。
もしあなたの header と footer が含まれているのであれば、headerが含まれる前にあなたの全ての機能ファイルを含めてください。
このエラーは、例外処理やその他の操作を伴う再帰を引き起こす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()呼び出しを含む行を指すため、実際には必要ありません。
私の場合、それは関数が書かれた方法に関する短い問題でした。メモリリークは、関数の入力変数に新しい値を代入することによって引き起こされる可能性があります。
/**
* Memory leak function that illustrates unintentional bad code
* @param $variable - input function that will be assigned new value
* @return null
**/
function doSomehting($variable){
$variable = 'set value';
// or
$variable .= 'set value';
}
yield
を使うことも解決策かもしれません https://www.php.net/manual/en/language.generators.syntax.php
より大きなメモリストレージ用にPHP.ini
ファイルを変更する代わりに、ループ内にyield
を実装すると問題が解決する場合があります。すべてのデータを一度にダンプするのではなく、大量のメモリ使用量を節約しながら1つずつ読み取ることができます。
Ini_set( 'memory_limit'、 '-1')を追加するだけです。あなたのWebページの一番上に行を入れます。そしてあなたは-1から16Mなどの場所であなたの必要性に従ってあなたの記憶を設定することができます。