12

質問:

実行中のアプリケーションでリークするリソースの種類のリストを取得する簡単な方法はありますか?アプリケーションに接続してIOW?

memproofでそれができることは知っていますが、速度が非常に遅くなるため、アプリケーションは1分も持続しません。ほとんどのタスクマネージャーのいいねは番号を表示できますが、タイプは表示できません。

チェック自体が壊滅的である(アプリプロセスを停止する)ことは問題ではありません。近づいているかどうかをタスクマネージャーでチェックできるからです(または少なくとも私は願っています)

リソースリークハンティング(メモリではない)に関するその他の洞察も歓迎します。

バックグラウンド:

私はDelphi7/2006/2009アプリ(3つすべてでコンパイル)を持っていて、約数週間後におかしな動作を開始します。ただし、実行する場所の1つでのみ、他のいくつかのシステムでは、電源が切れるまで実行されます。

問題を絞り込むために、いくつかのデバッグコードを挿入しようとしました。そして、ファイルの保存時に例外がEOutofResourcesであることがわかりました。(ファイルの保存は1日に何千回も発生する可能性があります)。

私はメモリリークを(fastmmで)推論しようとしましたが、データフローが非常に高いため(ギガビット産業用カメラから60MByte / s)、fastmmでのみ「忍び寄る」メモリリークを除外できます。それが起こる頃の記憶。何か問題が発生した場合、アプリは30分以内にメモリをいっぱいにします。

主な容疑者は、何らかのエラーとTMetafiles(これらのファイルにストリーミングされる)に何らかの形で残されたファイルハンドルです。マイナーな容疑者はVST、popupmenu、tframesです

更新:

もう1つの考えられるヒント:D7では2年間正常に動作しましたが、現在問題はTurbo Explorer(D2009に変換されていない安定したプロジェクトに使用しています)にあります。

Paul-Jan:それは週に一度だけ起こるので(そしてそれは夜に起こる可能性があります)、情報の取得は遅いです。それが私がこの質問をする理由です、私が木曜日にそこにいるときのためにものを組み合わせる必要があります。要するに:いいえ、100%確実かどうかはわかりません。Systemtoolsコレクション全体を持ってきて、何かを見つけることができるかどうかを確認するつもりです(それから、それは数日間実行されるためです)。開いているファイルが表示される可能性もあります。(たぶん、いくつかのmingw lsofを見つけて、それをスケジュールする必要があります)

しかし、アプリはGUIアクションをほとんど認識しません(マシンビジョン検査アプリです)。ただし、画面の更新+/- 15/sはtbitmapstretchdraw+ tmetafileですが、ディスク(TFileStream)ハンドルに保存するときにこのエラーが発生する可能性があります。疲れ果てた。ただし、同じストリームで、TMetafileもsavetostreamedされます。これは、後のアプリにはもう存在しないものであり、数か月から実行できます。

- - - - - - - - - - アップデート

私は検索し、検索し、検索し、invitroで問題を2、3回再現することができました。問題は、memusageが+/- 256MB(システムには2GB)、ユーザーオブジェクト200、gdiオブジェクト500、予想よりも開いているファイルが1つではない場合に発生しました。

これは本当に例外ではありません。おそらくフレームの親を変更したために、少量のハンドルがリークしていることに気付きましたが(VCL内の何かがHPaletteをリークしているようです)、主な原因は別の問題であると思われます。TMetafileを再利用し、その間に.clearします。メタファイルをクリアしても、リソースのサイズは実際には(常に?)変更されないと思います。最終的には、tmetafileのプール全体の各メタファイルが最大サイズになります。20〜40以上のtmetafile(それぞれ数100ksになる可能性があります)を使用すると、デスクトップにヒットします。ヒープ制限。

それは理論ですが、お客様のデスクトップ制限を10MBに設定して確認しようと思いますが、変更がないか確認するまでに数週間かかります。この理論は、このマシンが特別である理由も確認しています(このマシンには、平均してわずかに大きいメタファイルがある可能性があります)。場合によっては、プール内のtmetafileを解放して再作成することも役立つ場合があります。

幸いなことに、これらすべての問題(tmetafileと親の変更の両方)は、新しい世代のアプリですでに設計されています。

特別な状況(およびテストウィンドウが非常に限られているという事実)のため、これはしばらくの間ですが、今のところ例としてデスクトップヒープを受け入れることにしました(GDILeaksのものも多少役に立ちましたが)。

監査でスレッドでのGDIタイプの使用が明らかになったもう1つのこと(ただし、(他の方法で使用または接続されていない)tmetafileのみをストリームに保存します。

-------------アップデート2。

デスクトップの制限を増やすと、問題が発生するまでの時間がわずかに増えるように見えました。

残念ながら、マシンが問題のない新しいバージョンのフレームワークに更新されたため、これについてこれ以上フォローアップすることはできません。

要約すると、古いフレームワークから新しいフレームワークへの3つの主要な変更が何であったかを述べることしかできません。

  • フレームの親を変更して画面を変更することはなくなりました。現在、非表示にして表示するフォームを使用しています。これが原因で非常にまれなクラッシュや例外(クリックするとクリックされる可能性があります)も発生したため、これを変更しました。クラッシュはすべてGUIの操作中に発生しましたが、主な問題のように自発的に発生したわけではありません。
  • クラッシュが発生したルーチンはTMetafileを処理しました。TMetafileは設計されており、より単純な独自の形式に置き換えられています。(基本的にOpengl頂点を持つ配列)
  • 描画は、tmetafileオーバーレイstrechdrawedがその上にあるtbitmapでは発生しなくなりましたが、OpenGLを使用しています。

もちろん、上記の部分の書き直しで変更され、非常に厄介な詳細のバグを修正したものもあります。上記のシステムを可能な限り分析したので、それは非常に悪いものでなければなりません。

プライベートメールでの議論の後、 2012年11月に更新:振り返ってみると、次のステップはメタファイルオブジェクトにカウンターを追加し、x * 1000回程度使用するたびにそれらを再インスタンス化して、何かが変わるかどうかを確認することでした。同様の問題が発生した場合は、動的に割り当てられた長寿命のリソースを定期的に破棄して再初期化できるかどうかを確認してください。

4

8 に答える 8

12

エラーが誤解を招く可能性はわずかですウィンドウの DC を取得できない場合、VCL は単純にEOutOfResourcesを報告します ( Controls.pasのTWinControl.GetDeviceContextを参照)。

GetDC()が NULL ハンドルを返す可能性があり、VCL が OS エラーを報告する必要がある理由は他にもあり、リソース不足の状態を想定していないためです (これを確実に可能にするには、Windows のバージョン チェックが必要です。しかし、VCLもそれを受け入れることができ、またそうすべきです)。

ウィンドウ ハンドルが無効になった結果、 EOutOfResourcesエラーが発生する状況がありました。本当の問題を発見したら、原因を見つけて修正するのは簡単でしたが、存在しないリソース リークを見つけようとして何時間も無駄にしました。

可能であれば、この例外につながるスタック トレースを調べます。それがTWinControl.GetDeviceContextからのものである場合、問題はあなたが考えているものではない可能性があります (もちろん、それが何であるかを言うことは不可能ですが、不可能なものを排除することが常に最初です)。どんなにありそうになくても、解決策を発見するためのステップ)。

于 2010-02-02T02:58:19.243 に答える
6

それらがGDIハンドルリークである場合は、ツールGDILeaksを使用するMSDNMagazine 2003年1月を参照してください。他のツールはGDIObjまたはGDIViewです。こちらもご覧ください

EOutOfResourcesの別のソースは、デスクトップヒープがいっぱいである可能性があります。大画面のビジーなターミナルサーバーでこの問題が発生しました。

リークしているファイルハンドルがたくさんある場合は、Process Explorerをチェックして、プロセスの開いているファイルハンドルを調べて、異常なものを見つけることができます。または、 !htraceコマンドでWinDbgを使用します。

于 2010-02-02T09:15:27.863 に答える
3

以前にこの問題に遭遇しました。私が知ることができたことから、Delphi は、Windows API が ERROR_NOT_ENOUGH_MEMORY を返すたびに EOutOfResources をスローする可能性があり、(ここでの他の回答で説明されているように) Windows はさまざまな条件で ERROR_NOT_ENOUGH_MEMORY を返す可能性があります。

私の場合、EOutOfResources は TBitmap によって引き起こされていました。特に、TBitmap のCreateCompatibleBitmapへの呼び出しは、pfDevice のデフォルトの PixelFormat で使用されます。システムに十分なメモリと十分な GDI リソースがある場合でも、Windows はデバイス依存のビットマップに使用できるメモリにかなり厳しいシステム全体の制限を課すようです (たとえば、このディスカッションを参照)。(これらのシステム全体の制限は、明らかに、Windows がビデオ カードのメモリにデバイス依存のビットマップを割り当てる可能性があるためです。)

解決策は、代わりにデバイスに依存しないビットマップ (DIB) を使用することです (ただし、これらのデバイスはパフォーマンスがそれほど高くない場合があります)。Delphi でこれを行うには、TBitmap.PixelFormat を pfDevice 以外に設定します。 この KB 記事では、デバイスに最適な DIB 形式を選択する方法について説明しますが、通常、アプリケーションが表示される各モニターに最適な形式を決定しようとする代わりに、pf32Bit を使用します。

于 2013-08-08T16:58:42.300 に答える
2

EOutOfResourcesを見たほとんどの時間、それはある種のハンドルリークでした。

MadExceptのようなものを試しましたか?

--jeroen

于 2010-02-01T22:45:03.810 に答える
2

「問題を絞り込むためにいくつかのデバッグ コードを入れようとしましたが、例外はファイルの保存時の EOutofResources であることがわかりました (ファイルの保存は 1 日に何千回も発生する可能性があります)。」

ここでは暗闇の中で撮影していますが、Windows API を使用して (GetTempFileName) 一時ファイルを作成していて、ファイル システム インデックスを吹き飛ばしたり、ファイル ハンドルを閉じるのを忘れたりしている可能性があります。

いずれにせよ、ファイルハンドルの問題であるというあなたの推測に同意します。あなたの症状と診断を考えると、それが最も可能性が高いと思われます。

于 2010-02-02T00:36:02.480 に答える
0

また、SysInternalsのProcess Explorerを使用して、アプリケーションのハンドル数を確認してみてください。ハンドルの漏れは非常に危険であり、時間の経過とともにゆっくりと発生します。

于 2010-02-02T06:32:51.070 に答える
0

私は現在、自分のコードのハンドルを明らかにリークしていないソフトウェアでこの問題を抱えています。したがって、リークがある場合は、コンポーネントのソースコードまたはVCLソースコード自体で発生している可能性があります。

ハンドル数とGDIおよびユーザーオブジェクト数は増加しておらず、何も作成されていません。Delticの回答は、メッセージが一種の赤ニシンであるコーナーケースを示しており、Allenは、ファイルの書き込みでさえこのエラーを引き起こす可能性があることを示唆しています。

これまでのところ、それらを追跡するために私が見つけた最善の戦略は、JCL JCLDEBUGスタックトレースバック、またはMadExceptの例外レポート保存機能を使用して、実際に失敗しているものを見つけるためのコンテキスト情報を生成することです。

次に、AQTimeには、リソースを作成したコードの場所とその呼び出し方法、およびハンドルの総数のカウント間のリンクを保持できるリソースプロファイラーなど、役立つ多くのツールが含まれています。MID RUNの結果を取得できるため、終了後に解放されていないリソースを検出することに限定されません。したがって、AQTimeを実行し、実行の途中で結果のキャプチャを実行し、数時間待ってから再度キャプチャします。ハンドル数を比較するには、2つの時点が必要です。念のためにそれは明白なことです。しかし、Delticsが賢明に指摘しているように、この例外クラスは、おそらくそうではないはずの場合に発生します。

于 2010-07-23T16:14:31.087 に答える