十分なメモリまたは十分なハンドルがありませんか?
-
28-09-2019 - |
質問
私は、カスタム(かなり良い)フレームワークが提供されている大規模プロジェクトに取り組んでおり、フォームとビューを表示するためにそれを使用する必要があります。
抽象的なクラスの戦略エディタ(フレームワークのいくつかのクラスから派生)があり、新しい戦略形式が開かれるたびにインスタンス化されます。
StrategyForm
(カスタマイズされたウィンドウフレーム)が含まれています StrategyEditor
.
StrategyEditor
含む StrategyTab
.
StrategyTab
含む StrategyCanvas
.
これは、1つのStrategyFormオブジェクトが実行時にメモリに割り当てられた場合に作成される多くのオブジェクトがあることを明確にするための大きなクラスのごく一部です。私のコンポーネントは、上記のこれらすべてのクラスを除いて所有しています StrategyForm
そのコードは私のコントロールにありません。
現在、実行時に、ユーザーは多くの戦略オブジェクト(新しいStrategyFormオブジェクトの作成をトリガーする)を開きます。 44の戦略オブジェクトでは、アプリケーションによって作成されたユーザーオブジェクトが約20k+に到達し、レジストリではハンドルのデフォルト量は10kであることがわかります。 ユーザーオブジェクトの詳細については、こちらをご覧ください。 さまざまなマシンでテストすることで、開いた戦略オブジェクトの数がメッセージをポップアップするためにメッセージが異なることが明らかになりました - 1つのm/cで44の場合、別のm/cで40になります。
メッセージがポップアップされるのを見ると、アプリケーションがゆっくりと応答することを意味します。より多くのオブジェクトで悪化し、その後、ウィンドウフレームとその後のオブジェクトの作成が失敗します。
私たちはまず、それが不十分な問題であると考えました。しかしその後 についてもっと読む new
C#で アプリがメモリがなくなった場合、例外がスローされることを理解するのに役立ちました。これはメモリの問題ではありません。私は感じています(タスクマネージャーは1.5GB+利用可能なメモリも示しました。)
M/C仕様
コア2デュオ2GHz+
4GB RAM
ページファイル用の80GB+無料ディスクスペース
仮想メモリセット:4000-6000
私の質問
Q1。これは記憶の問題のように見えますか?
Q2。これは、無料のUOHS(私が考えているように)の疲労と、ウィンドウハンドルの作成の失敗をもたらすことを示していますか?
Q3。どのようにして、andのロードを避けることができますか StrategyEditor
オブジェクト(しきい値を超えて、UOHの現在の使用に目を向ける)? (使用中のUOHの数を取得する方法はすでにわかっているので、そこに行かないでください。) その呼び出しを覚えておいてください new StrategyForm()
私のコンポーネントの制御外です。
Q4。私は少し混乱しています - 何ですか ユーザーオブジェクトへの処理 まさに? MSDNは、作成するオブジェクト、またはウィンドウハンドル、カーソルハンドル、アイコンハンドルなどの特定のオブジェクトのみについて話しているのですか?
Q5。 UOHを使い果たす原因は何ですか? (Q4とほぼ同じ)
私は私に知識のある答えを私に与えることができる人に本当に感謝しているでしょう。どうもありがとう! :)
アップデート
Stakxの回答に基づいて、開いているウィンドウはユーザーのみが閉じていることに注意してください。これは、あまりにも多くの子供の窓が開かれているMDIアプリの状況のようなものです。それで、 Dispose
いつでも電話をかけることはできません。
解決
Q1
あまりにも多くのUIコントロールを同時に作成しようとしているようです。メモリが残っていても、ハンドルが不足しています。簡単な、しかしかなり技術的な説明については、以下を参照してください。
Q4
私は理解しています ユーザーオブジェクト GUIの一部であるすべてのオブジェクトになります。少なくともWindows XPまで、Windows UI APIは USER.DLL
(Windowsを構成するコアDLLの1つ)。基本的に、UIは「Windows」で構成されています。ボタン、テキストボックス、チェックボックスなどのすべてのコントロールは、内部的に同じもの、つまり「Windows」です。それらを作成するには、Win32 API関数を呼び出します CreateWindow
. 。その関数は、作成された「ウィンドウ」(UI要素、または「ユーザーオブジェクト」)にハンドルを返します。
だから私はそれを想定しています ユーザーオブジェクトハンドル この関数によって返されるハンドルです。 (WinFormsは古いWin32 APIに基づいているため、 CreateWindow
働き。)
Q2
確かに、あなたはあなたが望むだけ多くのUIコントロールを作成することはできません。それらのすべてのハンドルは取得されました CreateWindow
ある時点で解放されなければなりません。 Winformsでは、これを行う最も簡単で安全な方法は、 using
ブロックまたは呼び出しによって Dispose
:
using (MyForm form = new MyForm())
{
if (form.ShowDialog() == DialogResult.OK) ...
}
基本的に、すべて System.Windows.Forms.Control
可能です Dispose
D、そして処分する必要があります。時々、それはあなたのために自動的に行われますが、あなたはそれに頼ってはいけません。いつも Dispose
UIは、それらを必要としなくなったときに制御します。
オンに注意してください Dispose
モーダルおよびモードレスフォームの場合:
- モーダルフォーム(で表示されます
ShowDialog
) それは いいえ 自動的に処分されます。上記のコード例に示されているように、あなたは自分でそれをしなければなりません。 - モードレスフォーム(で表示されます
Show
)ユーザーがいつ閉鎖されるかを制御できないため、自動的に処分されます。明示的に呼び出す必要はありませんDispose
!
Q5
UIオブジェクトを作成するたびに、Winformsは内部的に電話をかけます CreateWindow
. 。それがハンドルの割り当て方法です。そして、彼らは対応する呼び出しまで解放されません DestroyWindow
作られています。 Winformsでは、その呼び出しは介してトリガーされます Dispose
任意の方法 System.Windows.Forms.Control
. (注:私はこれについて確実に確信していますが、私は実際に少し推測しています。私は100%正しいことではないかもしれません。反射器を使用してWinformsの内部を見ると真実が明らかになります。)
Q3
あなたのと仮定して StrategyEditor
大量のUIコントロールを作成しますが、私はあなたが多くのことができるとは思いません。そのコントロールを単純化できない場合(それが作成する子供のコントロールの数に関して)、あなたがいる状況で立ち往生しているようです。あなたは単に できません 無限に多くのUIコントロールを作成します。
しかし、あなたは何人を追跡することができます StrategyEditor
sはいつでも開かれます(カウンターがインスタンス化されるたびにカウンターを増やし、閉じたときはいつでも減少します - 後者を使用して追跡できます FormClosing
/FormClosed
フォームのイベント、または Dispose
コントロールの方法)。その後、開くと同時に数を制限できます StrategyEditor
s固定番号、たとえば5.制限を超えた場合、コンストラクターに例外をスローすることができ、これ以上のインスタンスが作成されないようにします。もちろん、私は言うことができません StrategyForm
あなたからの例外を処理するつもりです StrategyEditor
コンストラクターがよく...
public class StrategyEditor : ...
{
public StrategyEditor()
{
InitializeComponent();
if (numberOfLiveInstances >= maximumAllowedLiveInstances)
throw ...;
// not a nice solution IMHO, but if you've no other choice...
}
}
どちらの場合でも、インスタンス化の数を制限します StrategyEditor
Sは私にとって一時的な修正のように思えますが、本当の問題は解決しません。