0

私はJavaでネットワーキングプログラムを書いています。ServerSocket および Socket オブジェクトを使用して、TCP を使用してメッセージを送受信します。私のプログラムは、短時間実行すれば問題なく動作しますが、長時間実行すると、次のエラーが発生します。

java.net.SocketException: No buffer space available (maximum connections reached?): connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)

すべてのソケットを閉じていないためかもしれないと思いましたが、コードを変更しました。新しいソケットが必要なときに作成するクラスが 1 つあり、それを閉じるために finalize メソッドを追加しました。ServerSocket を閉じるための finalize メソッドもあるので、何が問題なのかわかりません。

また、エラーが発生した後、すぐにプログラムを再実行すると、以前よりも早く問題が発生します。その後、しばらく待って実行すると、元の時間のように戻ります。

私は本当に問題を解決することができず、私は何年もの間それを理解しようとしてきました. 誰が問題が何であるか知っていますか?

前もって感謝します!

アップデート:

だから私はエラーがどこから来ているのかを理解しました、そしてそれは本当に奇妙です. 問題を引き起こしている次のコードがあります。

try {
        sock = new Socket(InetAddress.getByName(ipaddr), port);
        sock.close();

        // os = sock.getOutputStream();
        // byte[] arr = s.getBytes();
        // os.write(arr);
        // os.close();

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            sock.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

ご覧のとおり、コードはソケットを開いて書き込む必要があります。ただし、上記のようにすべての機能コードがコメントアウトされている場合でも、ソケットが開かれてすぐに閉じられても、「バッファ領域がありません」というエラーが発生します。

これがなぜなのか、私には本当にわかりません。プログラムはマルチスレッド化されており、各スレッドは上記のメソッドを使用して定期的にオブジェクトを作成し、それを呼び出します。ソケットを作成して閉じる行が削除されると、エラーは発生しなくなりますが、そこにある場合、ソケットを開いてすぐに閉じてもエラーが発生します。

なぜこれが起こっているのか、誰にも手がかりがありますか?

どうもありがとう。

4

2 に答える 2

5

新しいソケットが必要なときに作成するクラスが 1 つあり、それを閉じるためにfinalizeメソッドを追加しました。ServerSocket を閉じるためのfinalizeメソッドもあるので、何が問題なのかわかりません。

うーん。止まる。小切手。ファイナライザーは、実行時に非決定論的です (ただし、Java アプリが終了した場合でもオブジェクトに到達できなくなった後を除きます!) - Destroying and Finalizingを参照してください。などの明示的なコントラクトを使用していることを確認し、Closableそれを何度も呼び出します (GC が発生するのを待たないでください!)。

この問題は、外部リソースの「リーク」を最もよく示しています。GC は主にメモリとメモリのプレッシャーに関心があるため、プレッシャーがほとんどない場合や GC が積極的でない場合、最初に外部リソースを使い果たすのは非常に簡単です。ファイナライザーは (まだ) 実行されていません。一般に、ファイナライザーは安全策 (常に機能するとは限りません) ですが、他の形式の外部リソース管理に代わるものではありません。

上記のリンクから:

Java は、ガベージ コレクションがいつ発生するか、またはオブジェクトがどのような順序で収集されるかについて保証しません。したがって、 Java は、ファイナライザーが呼び出されるタイミング (または呼び出されるかどうか)、ファイナライザーが呼び出される順序、またはファイナライザーを実行するスレッドについて保証できません。

ハッピーコーディング。

編集:この関連する質問を参照してください:なぜ finalize() を実装するのですか? . Steve Jessop からの 2 番目の応答が気に入っています。

于 2010-12-14T06:53:00.693 に答える
2

finalizeリソースを閉じるために使用しないでください。確実に動作しません。

(リソース オブジェクトがすぐにファイナライズされず、リソースが不足する可能性があります。ファイナライザーがいつ実行されるかを制御することはできず、決して実行されない可能性があります。)

あなたがすべきことは次のようなものです:

    Resource resource = // allocate resource
    try {
        // Use the resource ...
    } 
    catch (SomeException ...) {
        // Deal with errors from using the resource
    } 
    finally {
        try {
            resource.close()}
        }
        catch (SomeException ...) {
            // Deal with errors from closing the resource
        }
    }
于 2010-12-14T07:00:09.850 に答える