2012-04-12 14 views
0

私はC#で書かれたマルチスレッドTCPサーバーを持っています。クライアントはサーバによって受け入れられ、接続されたときにサーバから離れることはありません。約1300のアクティブな接続の後、私のソフトウェアはSystem.OutOfMemmoryExceptionエラーを出します。この問題は、32ビットシステムのアーキテクチャとRAMに関連していますか?私は32ビットのWindows 7 Professionalと4 GBのRAMを持っています。私のサーバーに約1300のアクティブな接続が存在する場合、私のmemmoryの使用量は約2.1GBで、CPU使用率は30%です。C#System.OutOfMemmoryException TCPサーバーで

ありがとうございます。

+1

私はそう思います...とにかく、あなたのアプリケーションは32ビットアーキテクチャで2 GB以上のメモリを認識しません。 –

+0

接続ごとのスレッドがありますか、またはスレッドプールを使用していますか? – Nick

+0

私は彼が最初のものを持っていることを知っています。 – AgentFire

答えて

5

System.OutOfMemmoryExceptionは、プロセス内の〜1300スレッドが(32ビットOSで)作成されたときにスローされます。そして、問題は、あなたが各接続のためのブランドの新しいスレッドを作成しているということです。それは悪い習慣です。

代わりに、送信データを管理するスレッドを1つだけ使用する必要があります。送信するスレッドと同じスレッド(または2番目のスレッド)を使用してください。 1つしか接続を受け付けません。

すべてのクライアントを受け入れるスレッドプールのコード例:

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90); 
bool isListening; 

public void BeginAccept() 
{ 
    while (isListening) 
    { 
     TcpClient tcpClient; 

     try { tcpClient = tcpListener.AcceptTcpClient(); } 
     catch { /* Swallowing is bad */ } 

     // TODO: Add your brand new tcpClient to some sort of collection, may be. 
    } 
} 
+1

ああ、私はスレッドを言及するつもりでした!私は、デフォルトのスタックサイズは1MBだと思います。 – Nick

+0

私はすべてのデバイスにスレッドをオープンしたいので、これは不可能だと思います。どのように私はスレッドのプールを使用できますか? – sanchop22

+0

私はすべてが可能だと思います。各デバイスのスレッドを保持する理由は何ですか? – AgentFire

0

あなたはAsynchronous Server Socketの実装をご覧ください:すべてのクライアントを受け入れる一つのスレッドのための

TcpListener tcpListener = new TcpListener(IPAddress.Any, 90); 

public void BeginAccept() 
{ 
    try { tcpListener.BeginAcceptTcpClient(AcceptClient, null); } 
    catch { /* Swallowing is bad */ } 
} 

private void AcceptClient(IAsyncResult ar) 
{ 
    TcpClient tcpClient; 

    try { tcpClient = tcpListener.EndAcceptTcpClient(ar); } 
    catch { /* Swallowing is bad */ } 
    finally { BeginAccept(); } 

    // TODO: Add your brand new tcpClient to some sort of collection, may be. 
} 

コード例。
キュー/ TCP再送信を避けるために、別のスレッドで応答を送信することをお勧めします。
タスクを使用するか、関連する接続で受信したメッセージを、処理中のクルーが処理している並行キューに追加することができます。

0

あなたのコンピュータ/ OSは、制限要因ではありません。プロセスあたり約4GBを割り当てることができます(合計4GB以上を使用すると、ディスクへのスワップ/書き込みが開始されます:これは通常のメモリよりもはるかに遅いですが、動作します)。 しかし、C#コンパイラはあなたを制限しています。 C#はデフォルトで32ビットでコンパイルされます。つまり、各プロセスは約2GBのメモリしか使用できません。これは、サーバーが2GBに達するとクラッシュする理由です。 64ビットOS用にコンパイルすると、事実上無制限のメモリを使用できますが、64ビットOSを持たないため、マシン上では動作しません。

スレッドではなく、クライアント接続ごとに新しいプロセスを作成することをお勧めします。メインプロセスは接続をリッスンして受け入れ、新しい接続が確立されると、そのクライアントとの接続を処理するだけの新しいプロセスが生成されるはずです。各接続には独自のプロセスがあるため、2GBの制限を超えることはありません。さらに多くの利点があります。接続が閉じられると、メモリの再利用が簡単になり、1つの接続のエラーがプログラム全体をクラッシュさせにくくなります。 もちろん、マルチプロセスアーキテクチャのプログラミングは、共有メモリがないのでマルチスレッドのプログラミングよりもやや困難ですが、ここではより良いアプローチです。

関連する問題