2012-01-23 2 views
4

Я реализовал простой сервер-клиентский чат в Java. Здесь источник - источник:Темы Java: утечка памяти

public class Server { 
    final private static int PORT = 50000; 

    private static class Read extends Thread { 
     private static Socket socket; 
     private static String address; 

     public Read(Socket socket) { 
      this.socket = socket; 
      address = socket.getInetAddress().toString().substring(1); 
     } 

     public void run() { 
      try { 

       BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       String msg; 

       while (true) { 
        msg = in.readLine(); 
        if (msg == null) { 
         in.close(); 
         return; 
        } 

        System.out.println(address + ": " + msg); 
       } 

      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

     } 
    } 

    private static class Write extends Thread { 
     private static Socket socket; 

     public Write(Socket socket) { 
      this.socket = socket; 
     } 

     public void run() { 
      try { 

       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
       BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); 
       String msg; 

       while (true) { 
        if (socket.isClosed()) { 
         out.close(); 
         return; 
        } 
        if (stdin.ready()) { 
         msg = stdin.readLine(); 
         out.println(msg); 
        } 
       } 

      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

     } 
    } 

    public static void main(String[] args) throws IOException { 
     ServerSocket serverSocket; 
     boolean listening = true; 

     serverSocket = new ServerSocket(PORT); 

     while (listening) { 
      Socket socket = serverSocket.accept(); 
      String address = socket.getInetAddress().toString().substring(1); 
      System.out.println("Connection Established " + address); 

      Thread read = new Read(socket);  
      Thread write = new Write(socket); 

      read.start(); 
      write.start(); 

      try { 
       read.join(); 
       write.join(); 
      } catch(InterruptedException e) { 

      } 

      socket.close(); 
      System.out.println("Connection Closed " + address); 
     } 
     serverSocket.close(); 
    } 
} 

Он работает нормально, но есть проблемы. Для каждого установленного соединения память постоянно растет. Я предполагаю, что проблема в том, что память, выделенная для потоков, не будет выпущена впоследствии, но я не совсем уверен. Как я могу это исправить?

EDIT: Клиентская программа:

class Client { 
    final private static int PORT = 50000; 

    private static class Read extends Thread { 
     private Socket socket; 
     private String address; 

     public Read(Socket socket) { 
      this.socket = socket; 
      address = socket.getInetAddress().toString().substring(1); 
     } 

     public void run() { 
      try { 

       BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
       String msg; 

       while (true) { 
        msg = in.readLine(); 
        if (msg == null) { 
         System.out.println("Connection closed " + address); 
         System.exit(0); 
        } 
        System.out.println(address + ": " + msg); 
       } 

      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

     } 
    } 

    private static class Write extends Thread { 
     private Socket socket; 

     public Write(Socket socket) { 
      this.socket = socket; 
     } 

     public void run() { 
      try { 

       PrintWriter out = new PrintWriter(socket.getOutputStream(), true); 
       Scanner sc = new Scanner(System.in); 
       String msg; 

       while (true) { 
        msg = sc.nextLine(); 
        out.println(msg); 
       } 

      } catch (IOException e) { 
       e.printStackTrace(); 
      } 

     } 
    } 

    public static void main(String[] args) throws IOException { 
     PrintWriter out; 
     BufferedReader in; 
     Scanner sc = new Scanner(System.in); 
     while (true) { //for the test only 
      Socket socket = null; 
     try { 
      socket = new Socket("78.90.68.125", PORT); 
     } catch(java.net.ConnectException e) { 
      System.out.println("Connection error: host unreachable"); 
      System.exit(1); 
     } 
/* 
     String address = socket.getInetAddress().toString().substring(1); 
     System.out.println("Connection established " + address); 
     Thread read = new Read(socket);  
     Thread write = new Write(socket); 

     read.start(); 
     write.start(); 

     try { 
      read.join(); 
      write.join(); 
     } catch(InterruptedException e) { 
      e.printStackTrace(); 
     } 
     finally { 
*/  
     socket.close(); 
//  } 
     //System.out.println("Connection closed " + address); 
     } 
    } 
} 

ответ

4

Попробуйте сделать

private static class Read extends Thread { 
private static Socket socket; 
private static String address; 

и

private static class Write extends Thread { 
private static Socket socket; 

к нестатическому.

Кроме того, я не знаю, как вы проверяете память, но помните, что Java собрал мусор, и вы увидите увеличение использования памяти изначально до тех пор, пока сборщик мусора (GC) не соберет его и не увеличится до следующего запуска GC , Таким образом, он постоянно увеличивается без какого-либо падения в течение длительного времени, только тогда есть утечка памяти, иначе вы хорошо пойдете.


Я побежал код выше как и побежал в течение приблизительно 1-2 часов, и это устойчивое использование памяти около 54Мб на компьютере Mac с использованием JDK 6. Я не использую JConsole, которая поставляется с JDK, чтобы увидеть MEM Применение. Я не нашел проблем.

Ниже приведен график, как я уже упоминал в своих ансах, у вас есть пик и окунание. В конце, когда я остановил клиента, он плоский. enter image description here

+0

Я использую системный монитор для проверки на наличие памяти.Программа достигает 70 мб, а затем клиент выдает исключение: «Исключение в потоке» main «java.net.NoRouteHostException: не может назначить запрошенный адрес». Изменение полей на нестатические не сработало. – svs

+0

Каков твой клиент? Сколько соединений у вас есть во время сбоя? Согласно вашей логике, похоже, что только одно соединение выполняется в любое время? – havexz

+0

Чтобы проверить сервер, я изменил клиент так, чтобы он выглядел как 'while (true) { Розетка сокета = новая Socket (« IP », PORT); .... socket.close(); } ' – svs

2

Попробуйте поместить свой socket.close() внутри блока наконец, чтобы убедиться, что она работает.

Но я думаю, что ваш код может иметь большие проблемы в этом, так как вы не используете пул соединений, вы бесполезно открываете новые подключения.

4

Ivan,

несколько вещей для работы с Threading.

Никогда не делайте этого:

try { 
    read.join(); 
    write.join(); 
} catch(InterruptedException e) { 
} 

Всегда положить что-то в пункте улова, и будь это log.error. У вас нет шансов узнать, что это происходит.

Затем все потоки/закрытие и т. Д. Должны входить в блок finally. В противном случае вы не можете обязательно закрыть все необходимое.

Возможно, вы захотите повторно подключиться. Попробуйте следующее: http://commons.apache.org/pool/

Не могли бы вы рассказать нам, если вы достигнете sysout для закрытия соединений? В основном старайтесь создавать записи журнала каждый раз, когда вы открываете соединение и каждый раз, когда вы его закрываете. Вероятно, вы видите, чего не хватает.

Смежные вопросы