web-dev-qa-db-ja.com

致命的なエラー:メモリ不足ですが、メモリが十分にあります(PHP)

私の質問はどんどん長くなっているので、質問全体を書き直して、より短く短くすることにしました。

8GBのメモリを搭載した専用サーバーでWebサイトを実行しています。私はphp.ini設定のメモリ制限を上げる必要があることを完全に認識しています。 128Mから256Mに-1に設定しました。それでも問題は持続性です。

致命的なエラー:D:\ www\football\views\main.phpの81行目のメモリ不足(786432の割り当て)(24576バイトを割り当てようとしました)

メモリ不足は意味がありません。これは、786432バイトしか割り当てられておらず、さらに24576バイトが必要だからです。

786432バイトは768キロバイトで、かなり小さいです。

ヒント

  • エラーは非常にランダムな行で発生します。行番号81で常にエラーになるとは限りません。
  • ピーク時には、Apacheは約500MBのメモリしか消費しません。まだ6GBの空きがあります。
  • 無限ループはありません。
  • スクリプトには1,042,424バイトが必要です。 echo memory_get_peak_usage();からこの番号を取得
  • MySQLの結果セットは小さい(最大で12行、純粋なテキスト、blobデータなし)
  • Important)2日に1回Apacheを再起動すると、エラーはなくなります。通常、Apacheが2日以上実行されている場合に発生します。
  • スクリプトのプロファイリングを含めましたが、それを入手できます ここ
  • この専用サーバーは、1つのWebサイトのみを実行するためにのみ使用されます。このWebサイトは、1分あたり平均1,000人の訪問者を持つトラフィックの多いWebサイトです。ピーク時には、1,700〜2,000の訪問者が同時にアクセスします。

サーバー仕様

OS:Windows 2008 R2 64ビット
CPU:Intel Core i5-4コア
RAM:8 GB
Apache 2.2
PHP 5.3.1
ストレージ:2 x 1 TBハードドライブ
帯域幅:10 TB毎月

解決

私はついに問題を調整して修正しました。改善のためにしたことをここで共有したいと思います。

  1. favicon.icoが欠落していたため、ルートエンジンが台無しになりました。ルートエンジンは非常に小さいですが、favicon.icoを含めることで、ルートエンジンを実行しないことでメモリ使用量を削減できます。私のウェブサイトの大部分にそれがあり、この新しいセクションにそれを置くのを忘れました。
  2. Limit MaxRequestPerChildが役立ちます。他の専用サーバーでは、MaxRequestPerChildが制限されています。このサーバーでは、0に設定しました。各スクリプトは分離されていると常に考えていました。私のスクリプトの実行に800kbかかったとしましょう。 ApacheまたはPHPが完了すると、800kbのメモリが解放されます。この方法では機能しないようです。制限されたMaxRequestPerChildは、制限されたMaxRequestPerChildと古いプロセスが死んでいる後に新しいプロセスを作成することにより、メモリリークを防ぐのに役立ちます。これが私の新しい設定です。

    ThreadsPerChild      1500
    MaxRequestsPerChild  10000 
    
  3. ob_flush();は、メモリをわずかに削減します。それはあまり役に立ちませんが、あらゆる最適化が役立ちます。

  4. この質問に答えようとする人々によって提案されたように、私はこれまで使用したことのないxdebugを使用しました。私はそれが素晴らしいツールであると言わなければなりません、そして、私はそれがわずかにより速く動くようにいくつかのものを最適化しました。
  5. いくつかの不要なApacheモジュールを無効にしました。私はそれを1つずつ無効にし、別の1つを無効にする前に完全に機能することを確認するために数日間テストを残そうとしています。不要なPHP拡張機能はすべて無効になりました。
  6. このサーバーの私のスクリプトのほとんどは、従来の方法を使用しました(テンプレートなし、データベース層なし、純粋なPHP、HTML、およびレガシーmysql_ *関数)。正直に言うと、非常に高速で実行され、非常に小さなメモリを使用しました。ただし、Webサイトが長くなっているため、スクリプトのメンテナンスは非常に簡単ではありません。ウェブサイトの一部を適切なフレームワーク(自分の小さなフレームワーク)に変換しようとしました。フレームワークが小さいため、独自のフレームワークを使用した理由(フレームワーク全体で3kbで、必要なものだけが含まれています)。
  7. この問題を完全に解決するIIS7.5への切り替え
60
invisal

スワップを使用しようとすると、サーバーが死ぬという同じ種類の問題に遭遇しました。これは、mod_phpがメモリを解放しないためです。そのため、Apacheプロセスは、ApacheまたはPHPのメモリ制限に達するか、制限がない場合はサーバーをクラッシュさせて成長し続けます。

Apacheを再起動すると、新しい新しいスリムプロセスが生成されますが、PHPスクリプトを長期にわたって実行すると、問題が発生するまで成長します。

解決策は、一定数のクエリが提供された後、Apacheがプロセスを強制終了するようにして新しいクエリを作成することです( (それに関連するいくつかの質問MaxRequestsPerChild 設定オプションを減らしますから、100(デフォルトは1000)としましょう。

もちろん、これにより、新しいプロセスを強制終了して生成するためにリソースが必要になりますが、少なくともサイトは機能し続けます。パフォーマンスを高く保つために実行中のプロセスの数を増やしたいと思うかもしれません。PHP(またはApache)メモリ制限x最大プロセス数がサーバーの物理RAMを超えないようにしてください。

これが私の経験です。

27
greg

まず、memory_get_peak_usage()はここでは役に立ちません。割り当てられたメモリの量のみを返しますが、それはエラーの原因となった同じ数です。

memory_get_usageは、呼び出されたときに割り当てられているアクティブなメモリ量を返します。

ini_set('memory_limit', '256M');は、システムメモリ上のPHPのフットプリントの最大許容値を設定します。 OOMを768Kで取得している場合、それをアップしても問題は解決しません。

使用しているPHPのバージョンについては示されていませんが、すぐにアップグレードすることをお勧めします。 ZendのMemory Managerがメモリの割り当て解除に失敗するバグがいくつかあり、まったく同じ問題につながる可能性があります。

ローカルサーバーと運用サーバーの両方で、同じバージョンのOS、同じ長いビット、同じバージョンのPHPが実行されていますか?答えはノーになります。

ウィンドウmalloc()の問題とは無関係で、サブドメインであり、おそらくVirtualHost内にあり、768kのみを割り当てている場合、OSの問題のように聞こえます。

スクリプトにアクセスするときに、コマンドプロンプトからtasklistを実行します。追加のApacheスレッド、またはプロセス全体のメモリ使用量の急増が見られますか?

最後のアイデアは、テーブルの行/列の各ループの後にflush()ob_flush();を実行することです。これにより、バッファがクリアされ、問題が発生している場合にメモリが節約されます。

15
Mike Mackintosh

一部のアプリケーションでは最大50%高速であるため、PHPを5.4+にアップグレードすることから始めます。多数のメモリリークを修正しました。 becnhamrksを参照してください: http://news.php.net/php.internals/5776

8
maxwell2022

エラーはOut of memoryであり、Allowed memory size [..] exhaustedではないことに注意してください。

そのため、メモリリークはシステムの他の場所にあります。 mysqlサーバーは、この重いクエリの後に大量のシステムメモリを使用し、Apache/phpを物理的およびスワップなしで残す可能性があります。

これは、常に同じ行で(および/または同じスクリプトで)エラーを説明するはずです。

6
Luca Rainone

Xdebugをインストールし、プロファイラートリガーを有効にします。プロファイラーファイルを生成し、問題の原因を特定できない場合はcachegrindファイルを投稿します。

編集:もちろんメモリリークが発生するページのプロファイラーファイル!

6
Carmageddon

正しいphp.iniを編集していないか、PHPやWebサーバーを再起動していないと思います。

<?php phpinfo();の内容を含むphpinfo.phpページをdocrootに作成して、正しいphp.iniを変更していることを確認します。 Webサーバーが使用しているphp.iniファイルの場所に加えて、許可される最大スクリプトメモリも示します。

次に、ページにスタックトレースを追加して、これにつながった一連のイベントを確認できるようにします。次の関数は、致命的なエラーをキャッチし、何が起こったかについての詳細情報を提供します。

register_shutdown_function(function()
{
    if($error = error_get_last())
    {
        // Should actually log this instead of printing out...
        var_dump($error);
        var_dump(debug_backtrace());
    }
});

個人的には、Nginx + PHP-FPMは、Apacheを遅くしてから長年使ってきたものです。

4
Xeoncross

ちょっと私も私のサーバーで同じ問題を抱えています。次のことを変更しました。

php.iniを変更...

memory_limit = 128M

httpd.confに追加します

RLimitMEM 1073741824 2147483648

apacheを再起動してエラーを削除しました:

3

MySQLと開いている接続の数に問題がある可能性があります。そのため、数日ごとに再起動すると自動的に整理されます。スクリプトのシャットダウン時に自動的に閉じますか?

3
Matt Humphrey

要約すると(元の質問からかなり離れたところにこの回答を追加しています):

  • PHPは、少量のメモリと思われるものを割り当てることができません
  • エラーが発生した時点での現在のメモリ使用量+要求された量が現在有効なメモリ制限よりも少ない
  • システムには、これが発生したときにPHPが使用できる6Gbがあります
  • 問題はApacheを再起動することで解決されるため-PHPがメモリを使用できないようにするのはApacheです

これらがすべて有効な場合、考えられる唯一の説明は、6Gbがvery断片化されているということです-これは少し考えにくいと思います。 ApacheからPHPを呼び出す方法-mod_phpを言わなかった? fpm? Fcgi?

上記の各述語、特に空きメモリの述語を調べることから始めます。 6Gbの空きがあることをどのようにして知りますかエラーが発生したとき?より可能性の高い原因は、あなたが発見していないメモリリークが発生していることです。

Apacheの構成方法の詳細は提供していません。また、MaxRequestsPerChildとMaxMemFreeを減らすことも検討しました。 (これはスレッドごとに適用されるワーカーApacheにはあまり馴染みがありません-実際にはプロセスごとに制限が必要です)。 Apache構成からコア設定を提供した場合、さらに提案を行うことができます。

Ajaxを広範囲に使用している場合を除き、キープアライブ時間が2以下であることを確認してください。

2
symcbean

致命的なエラー:メモリ不足(割り当て済みSOLVED
iも同様の問題を抱えており、何ヶ月も解決策がありませんでした。最後に、Apacheフォルダの1つ(つまり\ Apache\conf\extra)をチェックインしていましたが、Apacheのメモリ割り当てを制御するこのファイルに遭遇しました。ファイル名はhttpd-mpmです。このファイルでは、2048に設定されているMaxMemFreeを増やして、最初のMaxMemFree(IfModule!mpm_netware_module)で10000に設定してから2番目の5000個のIfModule mpm_netware_moduleのMaxMemFree。

これらは私の問題を解決しました。それが役に立てば幸い

2
Bilyaminu K

これは数日前に私に起こりました。新たにインストールしたのですが、それでも起こりました。誰もが見ている限り、サーバーの仕様に基づいています。ほとんどの場合、無限ループです。 PHPコード自体ではなく、Apacheへのリクエストにある可能性があります。

このURLにアクセスしたときに言うことができますhttp:// localhost/mysite/page_with_multiple_requests

Apacheが複数のリクエストを受信した場合は、Apacheのアクセスログを確認してください。その要求をトレースし、システムに「ボトルネック」を引き起こす可能性のあるコードをチェックアウトします(sendmailを使用する場合の私のexec())。話しているボトルネックは「無限ループ」である必要はありません。終了するまでに時間がかかる関数である可能性があります。または、PHPのいくつかの「 プログラム実行関数

Ajaxリクエスト(ページの読み込み時に実行されるリクエスト)もチェックする必要があるかもしれません。そのajaxリクエストが同じURLにリダイレクトする場合

例えばhttpx:// localhost/mysite/page_with_multiple_requests

リクエストをもう一度やり直します

ランダムな行や、スクリプトが終了するコード自体を投稿すると、「ループ」コードがどこかにある可能性があります。 imho phpは、ランダムな行を無料で呼び出すだけではありません。

http://blog.piratelufi.com/2012/08/browser-sending-multiple-requests-at-once/

1
kapitanluffy

PHPでも同様の問題が発生しました。

1)エラーログを確認します。続行する前にすべてのエラーを取り除きます。 2)未使用のモジュールを削除するためにApache構成を変更することを検討してください-これはPHPが必要とするフットプリントを削減します-これに対する素晴らしいリンクがあります-Wordpressに固有ですが、それでも非常に便利です http://thethemefoundry.com/blog/optimize-Apache-wordpress/

私が見つけたバグの種類のアイデアを与えるために、Facebookにコンテンツを投稿しようとするコードがあり、FacebookがAPIを変更してこれが壊れたので、基本的に再試行を続けることを意味する「コンテンツエクスピレーター」を使用しましたこのコンテンツをFacebookに投稿し、大量のオブジェクトをメモリに残します。

1
Dave Hilditch

Fcgidでphpを実行してみてください。これが役立つ場合があります。

これらは、ApacheモジュールとしてPHPを実行したときに表示される典型的なエラーです。私たちはこれらのエラーに何ヶ月も苦労しました。 mod_fcgid経由でPHPを使用するように切り替えると(Jamesが推奨しているように)、これらの問題はすべて修正されます。最新のVisual C++再頒布可能パッケージがインストールされていることを確認してください。

http://support.Microsoft.com/kb/2019667

また、MySQLの64ビットバージョンに切り替えることをお勧めします。 32ビットバージョンを実行する本当の理由はもうありません。

ソース: php5ts.dll 5.5.1.0の問題によるApache 2.4.6.0のクラッシュ

1
Igory

プロファイラーの出力ファイルから、私はあまり好きではない/信頼していないいくつかのことに気づき、これらを調べます:

異常を検出するための出力番号の意味や、PHPスクリプトの動作を知らないことは別として...、これは問題ではないでしょうか?同じmain.phファイルにインクルードがあると、これは再帰的なもののように見えますか?

2121 fl=D:\www\football\views\main.php
2122 fn=include::D:\www\football\views\main.php

ファイルD:\www\football\views\main.phpはいくつかの文字列関数を数回使用していることに注意してください。クエリによって返されたデータに対してこれらの関数を呼び出していると思います。

strlen
substr
strtotime

C言語のように、これらの関数がメモリの問題を回避するために文字列をnull終端するか、文字列の終端の終端を必要とする場合、クエリによって返される文字列を調べます。

ウェブサイトのURLを投稿できますか?

1
Only You

ほとんどの場合、このようなエラーが発生する場合、問題はコードにあります。私はあなたが悪いコードを書いていると言っているのではなく、この量のメモリを使用しているものを注意深く観察する必要があると言っているのです。

常に「PHPのガベージコレクションはかなり悪い」を覚えておいてください。これはJavaや他の言語とは異なります。 gc_collect_cycleを使用してガベージコレクションを強制する方法がありますが、私の個人的な意見では、それはあなたの問題を解決しません。 PHPリクエスト/レスポンスサイクルが完了すると、ページの実行に使用されるすべてのメモリが解放されるため、バックグラウンドスクリプト(ギアマンなど)のようにスクリプトが長時間実行されると、メモリの問題が発生する可能性があります。スクリプトが実行されるまでメモリは解放されません。

上記がscr、ptに当てはまらず、非常に大量のメモリを必要とするコードがないと言った場合、問題はコード自体にあり、PHPは問題を解決しません。 Gearmanスクリプトの1つに一度直面したことがあり、1つの変数を配列の1つに追加するループの1つに問題がありました。変数自体は非常に重かった(約110KBのデータ)。したがって、コードを注意深く検査することをお勧めします。

派手な

1
Ravish

これはPHP v 5.2 for Windowsの既知のバグであり、少なくともバージョン5.2.3に存在します。 https://bugs.php.net/bug.php?id=41615

提案された修正はどれも役に立たなかったため、PHPを更新する必要があります。

1
Anonymous User

次の2つの事実は、間違いなくメモリリークを示しています。

  1. エラーはコードの異なる行に表示されますが、
  2. エラーは、比較的小さなメモリ割り当てを報告します。

最初にPDOを選び出し、他のすべての拡張機能を無効にして、Siege/Apache Bench(ab)などを使用して一晩実行します。 cliインターフェイスを使用して実行することもできます(同じメモリ制限を維持するようにしてください)。

スクリプトの最後に memory_get_peak_usage() 関数を使用すると、PHPが使用していると考えているメモリ量を確認できます。

あなたのコメントからは800 kBですが、それで問題ありません。メモリ不足を引き起こす巨大なメモリ量ではありません;-)

最後に、現時点では5.4にアップグレードすることはお勧めしませんが、5.3.1以降に対処された複数の脆弱性とリークがあるため、おそらく最新の5.3.xにアップグレードする価値があります。

1
Ja͢ck

サーバーの物理メモリまたはスワップメモリ​​が不足しているため、PHPは十分なメモリを割り当てることができません。

freeの出力をここに貼り付けられますか?

0
Edson Medina

私の場合、このエラーは巨大な選択クエリ(何十万もの結果が返されたため)が原因で発生しました。

WordPressのスケーラビリティをテストするためにデータベースに数百万のレコードを追加した直後に発生したため、それが唯一の理由でした。

0
AFA Med