Как правильно настроить поток для GC'd в Java? - PullRequest
1 голос
/ 28 декабря 2010

давний пользователь, первый постер ...

В любом случае, мне было интересно, как настроить созданный поток для GC'd. Я сделал простой многопоточный сервер для приема соединений от клиента, но каждый раз, когда клиент подключается, использование памяти увеличивается примерно на 80 тыс.… Понятно. Проблема в том, что я не знаю, как выйти из этого быстрого роста после того, как клиент и сервер отключились.

Вот основной класс, который устанавливает поток:

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 - не говоря уже о том, чтобы использовать потоки, поэтому, если это очевидно, пожалуйста, постарайтесь быть в этом хорошими. Спасибо за любую помощь, вы можете предоставить!

Ответы [ 3 ]

4 голосов
/ 28 декабря 2010

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. 
    }
  }
}
3 голосов
/ 28 декабря 2010
  1. Откуда вы знаете, что есть утечка памяти?Не похоже, что для меня есть утечка

  2. Вам не нужно ничего делать.Сборщик мусора всегда работает, и ему все равно, на объекты ссылаются из потока.Если нет, вы просто будете создавать потоки так же быстро, как и во время выполнения цикла.Я не эксперт здесь, так что если вызов вызова блокируется там до запуска потока, тогда это может быть хорошо.

2 голосов
/ 29 декабря 2010

Между этими двумя ответами я не вижу этой информации.GC очистит неактивные потоки, поэтому, если вы позволите потоку выйти из метода run (), он будет очищен GC.Любая память, на которую ссылаются из стека этого потока, будет очищена, если она неактивна, если никакие другие активные потоки не ссылаются на эту память из своего стека или статический корень не ссылается на нее (точка ответа 2 Фалмарри неверна или, по крайней мере, сформулирована неправильно).GC по большей части свободен от рук и автоматически, с вашей стороны мало работы, чтобы фактически освободить память при нормальных обстоятельствах.

Теперь память, которую вы видите, увеличивается при создании потока, иная.Как вы измеряете этот 80K прыжок?Вы используете диспетчер задач, топ или какой-либо инструмент ОС, чтобы увидеть этот удар?Инструменты ОС не очень помогают в истинном понимании того, что происходит внутри JVM.Это может быть освобождение внутренней памяти JVM, которую не видят инструменты ОС.Причина в том, что Java скупа на распределение памяти.Как только он выделяет больше памяти, он сохраняет его, даже если не использует его.Причина в том, что ОС не спешит раздавать память процессам.Удерживая его, если оно понадобится позже, и статистика говорит «да», тогда быстрее просто удержать его, чем освободить.Java вернет память, если у ОС недостаточно памяти или она использует очень мало памяти из общего объема.Это редко так.Java очень эффективна с ее распределением памяти.

Если вы хотите просмотреть память или увидеть больше подробностей, я бы предложил использовать jconsole, который поставляется с JVM.Он покажет вам внутреннюю часть JVM, чтобы вы могли видеть общую память, кучу и 4 пространства (eden, оставшийся в живых, постоянный, поколение Perm), которые составляют кучу.Вы также можете увидеть, сколько памяти занимает ваш код в пространстве Code Gen.Вы даже можете видеть, что ваши активные потоки работают в процессе, поэтому, если у вас есть застрявшие потоки, вы можете диагностировать это и там.И у вас есть возможность запросить GC, чтобы вы могли видеть, как ваше приложение использует память.

Весь смысл в том, что если вы считаете, что у вас есть утечка, вы можете начать понимать ее с помощью этого инструмента,Это супер просто, действительно информативно и бесплатно.Если у вас есть утечка, вам может понадобиться профилировщик памяти, например jprofiler, чтобы сообщить вам более подробную информацию.

...