2015-12-30 112 views
0

我有一個Socket,它通過ObjectOutputStream每隔幾秒向客戶端發送一個對象列表。在服務器端,在每個writeObject(myList)後執行flush然後reset。使用VisualVM檢查內存使用情況,在服務器上沒有內存泄漏,但在客戶端上,似乎先前讀取的列表保留在內存中。我試圖在客戶端的ObjectInputStream上執行reset,但看起來像ObjectInputStream不支持此方法(它會拋出java.io.IOException: mark/reset not supported)。ObjectInputStream消耗太多內存

這是我的服務器套接字:

public class ConsultaBombas { 

    public static void inicializarServidorSocket() { 
     try { 
      ServerSocket serverSocket = new ServerSocket(5963); 
      Thread thread = new Thread(() -> { 
       while (!serverSocket.isClosed()) { 
        try { 
         final Socket socket = serverSocket.accept(); 
         new ThreadComunicacao(socket).start(); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      }); 
      thread.setName("Consulta bombas (Inicializador)"); 
      thread.start(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    static class ThreadComunicacao extends Thread { 
     private Socket socket; 

     public ThreadComunicacao(Socket socket) { 
      this.socket = socket; 
      setName("Consulta bombas (Comunicação) com início: " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date())); 
     } 

     @Override 
     public void run() { 
      try { 
       ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream()); 
       while (!socket.isClosed()) { 
        List<Bomba> bombas = new DaoBomba().findAll(); 
        out.writeObject(bombas); 
        out.flush(); 
        out.reset(); 
        Thread.sleep(1000); 
       } 
      } catch (SocketException e) { 
       if (e.getLocalizedMessage() != null && e.getLocalizedMessage().equalsIgnoreCase("Connection reset by peer: socket write error")) { 
        System.out.println("Cliente desconectou..."); 
       } else { 
        e.printStackTrace(); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    } 

} 

的,這是(開始start()方法)的客戶端:

public class ConsultaBombasClient { 

    private Socket socket; 
    private Thread threadConsulta; 

    public ConsultaBombasClient(BombasListener bombasListener, String maquinaDestino) { 
     threadConsulta = new Thread(() -> { 
      try { 
       Thread.currentThread().setName("Consulta Bombas"); 
       System.out.println("Endereço bagual: "+maquinaDestino); 
       socket = new Socket(maquinaDestino, 5963); 
       ObjectInputStream in = new ObjectInputStream(socket.getInputStream()); 
       Object leitura; 
       while ((leitura = in.readObject()) != null) { 
        List<Bomba> bombas = (List<Bomba>) leitura; 
        bombasListener.run(bombas); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
       throw new RuntimeException(e); 
      } 
     }); 
     threadConsulta.setDaemon(true); 
    } 

    public void start() { 
     threadConsulta.start(); 
    } 

    public interface BombasListener { 
     void run(List<Bomba> bombas); 
    } 

} 

我到底做錯了什麼?

+0

BombasListener實現是否可能保留對之前列表的引用? – Berger

+0

我評論了BombasListener實現中的所有內容,只是爲了檢查這一點,但內存問題仍然存在。 –

+1

@MateusViccari,垃圾收集不是直接的,你有沒有真正的記憶麻煩?您是否嘗試過使用低'-Xmx'值運行客戶端,您是否收到'OutOfMemoryError'? – user3707125

回答

1

垃圾收集不是直接的,你有任何真正的記憶麻煩?您是否嘗試過運行低價值的客戶端-Xmx,您是否收到OutOfMemoryError? –   user3707125

你是對的,當記憶變得接近最大堆大小一段時間後,它從內存中清除的對象。我沒有看到這個,因爲我的電腦裏有很多RAM,但是用Xmx50m我可以看到這個工作正如你所說的。 - Mateus Viccari

0

很明顯bombasListener.run(),無論它是什麼,都不會釋放提供的列表。

NB ObjectInputStream.readObject()在流結束時不返回空值。因此,將此測試用作讀取循環的終止條件是不正確的。