2010-12-28 7 views
1

長時間のユーザー、初回投稿...JavaでGCするスレッドを正しく設定するにはどうすればよいですか?

とにかく、私は作成されたスレッドをGC'dに設定する方法を考えていました。私はクライアントからの接続を受け入れるための単純なマルチスレッドサーバーを作ったが、クライアントが接続するたびにメモリ使用量は約80k増加した。分かりやすい。問題は、クライアントとサーバーの接続が切断された後の急速な成長から戻ってくる方法がわからないことです。ここで

は、スレッドを設定し、メインクラスです:

public static void main(String[] args) { 

    try { 
    serverSock= new ServerSocket(9999); 
    } catch (IOException e1) { 
    // TODO Auto-generated catch block 
    e1.printStackTrace(); 
    } 

    while (true){ 
    try { 
    Thread t = new server(serverSock.accept()); 
    t.start(); 
    t = null; 
    } catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } 
    } 

    } 
} 

そしてここでは、基本的なサーバのスレッドです:

public class server extends Thread { 
private Socket serverSocket = null; 
public static String command = null; 

public server(Socket serverSocket2) { 
    super("server"); 
    serverSocket = serverSocket2; 
} 


@Override 
public void run(){ 
    BufferedReader fromClient = null; 
    PrintStream toClient = null; 
    String line = null; 
    String[] user = new String[2]; 

    try { 
    serverSocket.setSoTimeout(10000); 
    fromClient = new BufferedReader(new InputStreamReader(serverSocket.getInputStream())); 
    toClient = new PrintStream(serverSocket.getOutputStream()); 
    System.out.println("Got connection"); 
      System.out.println("Terminating server"); 
    fromClient.close(); 
    toClient.close(); 
    serverSocket.close() 
     } catch (NumberFormatException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (IOException e) { 
    System.out.println("Connection established, but timeout on" + 
    " message recieve may have occured"); 
    e.printStackTrace(); 
    } 
} 

、どのように正確に私はちょうどこのスレッドを可能にします...死んで、離れて行くのではなく、現在起こっているメモリリークを引き起こすのですか?

また、私はJavaに慣れていません - スレッドを気にしないでください。明白な場合は、それについて素敵なことを試してください。あなたが提供できるお手伝いをありがとう!

+0

't'を' null 'に設定しても効果はありません。その文の直後にブロックが終了し、 't'が範囲外になるからです。 @ Pete:スレッド実行中に 't'を' null'にするとどうなりますか?スレッドには何も悪いことはありません。 – Jesper

+0

私はスレッドサブクラスへのポインタを保持しない限り、他のオブジェクトのようにスコープ外に出た後にGCすることができるという印象を受けました。私は...ないと思う? – Pete

答えて

4

GCが必要なときに実行されるだけで、必要ではないように見えるので、クリーニングできるオブジェクト/スレッドは不要です。これはメモリリークがあることを意味するものではありません。それはメモリが必要でないことを意味します。

ところで、スレッドを直接拡張しないでください。代わりに、Executors.newCachedThreadPool()を使用することをお勧めします。これは短命のスレッドをはるかに効率的に処理します。

また、ServerSocketが例外をスローすると、これはリカバリできません。一度失敗すれば無限に失敗するということです。例外がスローされた場合は、それが起こらなかったかのように、それを印刷するのは一般的には悪い考えです。

際限なく失敗することはありません、あなたのメインの短いバージョンは、私はこの情報が表示されませんこれらの2つの答えの間

public static void main(String... args) throws IOException { 
    ServerSocket serverSock = new ServerSocket(9999); 
    ExecutorService es = Executors.newCachedThreadPool(); 
    while (true) 
     es.submit(new ClientHandler(serverSock.accept())); 
    } 
} 
class ClientHandler implements Runnable { 
    private final Socket socket; 
    public ClientHandler(Socket socket) { this.socket = socket; } 

    public void run() { 
    while(true) { 
     // do something with the socket. 
    } 
    } 
} 
+1

D4N14LはJavaの新機能であるため、Threadを直接拡張するのではなく、[Runnable'](http://download.oracle.com/javase/6/docs/api/java/lang)を実装する必要があることを指摘する必要があります。 /Runnable.html)を使用してください。 – Powerlord

+0

@R。 Bemrose、私はCallable を提案するつもりだったが、Runnableは良い選択です、ありがとうございました。 @ –

+0

@ R。 Bemrose:はい、以前のバージョンではRunnableを実装していましたので、実験していました...スレッドを拡張したコードを投稿したばかりです。しかし、ありがとう。 – D4N14L

3

1.)どのようにメモリリークがあるのですか?それは私に漏れがあるように見えません。

2)何もする必要はありません。ガベージコレクタは常に実行されており、オブジェクトがスレッドから参照されているかどうかは気にしません。

3)私が見る唯一のことは、serverSock.accept()ブロックがそこにありますか?そうでない場合は、ループ実行中に速くスレッドを作成するだけです。私はここでは専門家ではないので、受け入れ呼び出しがスレッドを開始する前にブロックしていれば、これは大丈夫かもしれません。

+0

'ServerSocket'の[' accept'](http://download.oracle.com/javase/6/docs/api/java/net/ServerSocket.html#accept%28%29)ブロック、はい。 – Powerlord

2

です。 GCはアクティブではないスレッドをクリーンアップします。そのため、スレッドがrun()メソッドを終了させると、GCによってクリーンアップされます。そのスレッドのスタックから参照されるメモリは、他のアクティブなスレッドがスタックからそのメモリを参照していない場合、またはスタティックルートが参照していない場合にはクリーンアップされます(Falmarriの答えポイント2は間違っているか、 GCはほとんどの場合ハンズフリーで自動ですが、通常の状況下で実際にメモリを解放するための作業はほとんどありません。

スレッドが作成されたときに上に表示されるメモリが異なります。この80Kジャンプをどのように測定していますか?そのバンプを確認するには、タスクマネージャ、トップ、または一部のOSツールを使用していますか? OSツールは、JVMの内部で何が起こっているかを真に理解するのにあまり役立つものではありません。 OSツールが見ることができないJVM内部のメモリを解放している可能性があります。その理由は、Javaはメモリ割り当てにぎっしりとしているからです。より多くのメモリを割り当てると、それを使用していなくても保持されます。理由は、OSがメモリをプロセスに渡すのが遅いためです。それを後でもう一度必要とする場合はそれを保持することによって、統計は「はい」と言います。それを解放するのではなく、単にそれを保持するだけです。 OSのメモリが不足している場合や、メモリ全体の使用メモリが非常に少ない場合は、Javaがメモリを戻します。しかしそれはまれです。 Javaのメモリ割り当ては非常に効率的です。

メモリを見たり、詳細を見るには、JVMに同梱されているjconsoleを使用することをお勧めします。ヒープを構成するメモリ、ヒープ、および4つのスペース(eden、survivor、tenured、Perm Generation)を表示できるように、JVMの内部を表示します。 Code Genのスペースでコードが占めるメモリの量を確認することもできます。あなたのアクティブなスレッドがプロセス内で実行されているのを見ることさえできます。スレッドが滞っている場合は、診断することもできます。また、GCをリクエストして、アプリがメモリをどのように使用しているかを確認することもできます。

このツールの使用によって、漏れがあると思われる場合は、この点全体を理解することができます。それは超簡単で、本当に有益で、無料です。リークがある場合は、jprofilerのようなメモリプロファイラが必要な場合があります。

+0

ありがとう、それは私のような初心者にとって非常に有益でした。はい、私はタスクマネージャを使用していました...後の問題のためにjConsoleを念頭に置いています。 – D4N14L

関連する問題