簡體   English   中英

您如何正確設置要在Java中使用GC的線程?

[英]How do you properly set up a thread to be GC'd in Java?

我想知道如何設置創建的線程以進行GC處理。 我制作了一個簡單的多線程服務器來接受來自客戶端的連接,但是每次客戶端連接時,內存使用量都會增加約80k ...這是可以理解的。 問題是,在客戶端和服務器斷開連接后,我不知道如何從快速增長中退縮。

這是設置線程的主要類:

public static void main(String[] args) {

   try {
      serverSock= new ServerSocket(9999);
   } catch (IOException e1) {
      e1.printStackTrace();
   }

   while (true){
      try {
         Thread t = new server(serverSock.accept());
         t.start();
         t = null;
      } catch (IOException e) {
         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的新手-不用介意使用線程,因此,如果很明顯,請嘗試對其進行改進。 感謝您的任何幫助,您可以提供!

GC僅在需要時運行,它似乎並不需要,因此可以清除的對象/線程不需要。 這並不意味着內存泄漏。 這意味着不需要內存。

順便說一句:您不應該直接擴展線程。 相反,我建議您使用Executors.newCachedThreadPool()。 這將更有效地處理短期線程。

同樣,當ServerSocket引發異常時,這是不可恢復的。 這確實意味着一旦失敗,它將無休止地失敗。 如果拋出異常,則將其繼續打印就好像沒有發生那樣,通常是一個壞主意。

不會連續失敗的主版本的較短版本是

    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. 您怎么知道內存泄漏? 看來我沒有泄漏

  2. 您什么都不需要做。 垃圾收集器始終在運行,並且不會[區分]從線程引用的對象與否。

  3. 我唯一看到的是, serverSock.accept()在那里阻塞? 如果沒有,那么您將僅以循環運行時的速度創建線程。 我不是這里的專家,因此,如果在啟動線程之前將accept調用阻塞在那里,則可以這樣做。

在這兩個答案之間,我沒有看到此信息。 GC將清除不活動的線程,因此,如果讓線程退出run()方法,它將被GC清除。 如果沒有其他活動線程從該線程的堆棧中引用該內存,或者沒有靜態根引用該線程,則從該線程的堆棧引用的所有內存都將被清除(Falmarri的回答第2點對此有錯誤,或者至少措辭錯誤)。 GC通常是免提的,並且自動運行,在正常情況下,您實際上不需要多少工作來釋放內存。

現在,創建線程時看到的內存有所不同。 您如何測量80K跳? 您是否正在使用任務管理器,top或某些OS工具來查看這種情況? 操作系統工具對真正了解JVM內部發生的情況並沒有太大幫助。 可能正在釋放OS工具看不到的JVM內部的內存。 原因是Java的內存分配很st。 一旦分配了更多內存,即使不使用它也會保留它。 原因是因為OS將內存分配給進程的速度很慢。 如果以后再保留它,並且統計數據說是肯定的,則通過保留它,然后保留它而不是釋放它會更快。 如果OS的內存不足或使用的內存很少,則Java將返還內存。 不過,這種情況很少。 Java的內存分配非常有效。

如果您想觀看內存或了解更多詳細信息,建議您使用JVM附帶的jconsole。 它將向您顯示JVM的內部結構,因此您可以看到總的內存,堆和構成堆的4個空間(eden,survivor,tenured,Perm Generation)。 您還可以在Code Gen空間中查看代碼占用了多少內存。 您甚至可以看到活動線程在進程中運行,因此,如果線程被卡住,也可以在那里進行診斷。 您可以選擇請求GC,以便查看應用程序如何使用內存。

這樣做的全部目的是,如果您認為有泄漏,則可以使用此工具開始理解它。 它非常簡單,真正有用,而且免費。 如果您有泄漏,則可能需要像jprofiler這樣的內存分析器來告訴您更多詳細信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM