1

以下のコードを書きましたが、ほぼ 150 回呼び出した後、"Exception in thread "Thread-245" java.lang.OutOfMemoryError: Java heap space" がスローされ、問題が発生しました (b = new byte[1024 * 1024] ;) Java コード:

class Client implements Runnable {
private Socket socket;
private BufferedInputStream bufin = null;
private BufferedOutputStream bufout = null;
String path;
private byte[] b;

Client(Socket socket, String path) {
    this.socket = socket;
    this.path = path;
}

@Override
public void run() {
    try {
        bufin = new BufferedInputStream(socket.getInputStream());
        bufout = new BufferedOutputStream(new FileOutputStream(path));

        b = new byte[1024 * 1024];
        int num = 0;
        while ((num = bufin.read(b)) != -1)
            bufout .write(b, 0, num);
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            bufin.close();
            bufout .close();
            b = null;
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

}

問題をより明確に説明しようとします。それは次のようなものです: 私は ServerSocket を書きます。クライアントがサーバーにリクエストを送信すると、次のように新しいスレッドにリクエストが送信されます。

public void start() {
      boolean started = false;
      try {
              ServerSocket ss = new ServerSocket(8888);
              started = true;
              while (started) {
              String path = "C:/Pic/"+ new SimpleDateFormat("yy-MM-dd-HH_mm_ss_ms").format(new Date()) + ".jpg";
              Socket s = ss.accept();
              new Thread(new Client(s, path)).start();
             }
       } catch (IOException e) {
              e.printStackTrace();
       }

}

この場合、サーバーは任意のクライアントからの要求を受け取ります...そして、問題がJavaヒープスペース例外を引き起こすと私が考える2番目の問題、つまり、サーバーが画像を受信すると、画像を削除できなくなりますサーバーを閉じる前にディスクを削除すると、「ファイルが Java(TM) プラットフォーム SE Binary で開かれているため、アクションを完了できません」と表示されます。私はすでにクライアントスレッドで入出力を閉じています。今、私は問題の根本を発見することはできません.1. なぜヒープ例外が発生するのか. お返事ありがとうございます!

4

2 に答える 2

0

ヒープが使い果たされているため、例外が発生した後、最終ブロックでプログラムが適切に動作せず、ストリームが開いたままになっていると思われます。ストリームを開く前にメモリ ブロックを割り当てるようにプログラムを変更することをお勧めします。さらに、finally ブロックでストリームを閉じるには、例で説明されているように IOUtils commons-io クラスを使用することをお勧めします。

閉じる静かに

byte[] data = "Hello, World".getBytes();

OutputStream out = null;
try {
 out = new FileOutputStream("foo.txt");
 out.write(data);
 out.close(); //close errors are handled
} catch (IOException e) {
 // error handling
} finally {
 IOUtils.closeQuietly(out);
}

これにより、すべてのストリームが finally ブロックで閉じられていることを確認できます。

于 2012-12-27T17:19:34.270 に答える
0

各スレッドが 1MB の配列バッファーを作成しているため、メモリが不足しています。最大ヒープ サイズを確認し (これはいくつかの変数に依存します)、コマンド ラインで最大サイズを増やします。例: java -Xmx1024M myclass.class

また、150 のクライアントを開始したとおっしゃいました。なぜ彼らはガベージコレクションを受けていないのですか? おそらく、150 個すべてが即座に開始され、すべてのスレッドが同時にそのメモリを取得しているのではないでしょうか? スレッド プールを使用してこれらを実行することをお勧めします。これにより、実行中のクライアント数に制限を設けることができます。

ファイルを保持しているサーバーの問題 (ファイルを削除できない) は、そのヒープ メモリ エラーが発生しているためです。これを取得すると、すべての賭けがオフになります。サーバーはまだファイルへの参照を保持しており、おそらく bufout.close() が機能していません。

于 2012-12-27T17:03:07.097 に答える