【问题标题】:ObjectInputStream consumes too much memoryObjectInputStream 消耗太多内存
【发布时间】:2015-12-30 16:07:50
【问题描述】:

我有一个 Socket,它每隔几秒就通过 ObjectOutputStream 向客户端发送一个对象列表。在服务器端,每个writeObject(myList) 之后我执行flush 然后reset。使用 VisualVM 检查内存使用情况,在服务器上没有内存泄漏,但在客户端上,之前读取的列表似乎保存在内存中。我尝试在客户端的 ObjectInputStream 上执行 reset,但看起来 ObjectInputStream 不支持此方法(它会抛出 java.io.IOException: mark/reset not supported)。

这是我的服务器套接字:

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);
    }

}

我做错了什么?

【问题讨论】:

  • BombasListener 实现是否有可能保留对先前列表的引用?
  • 我评论了 BombasListener 实现中的所有内容,只是为了检查这一点,但内存问题仍然存在。
  • @MateusViccari,垃圾回收不是即时的,你有什么真正的内存问题吗?您是否尝试过以较低的-Xmx 值运行客户端,是否收到了OutOfMemoryError
  • @MateusViccari,还有ObjectOutputStream.reset 文档明确指出它会自动重置相应的ObjectInputStream
  • 你是对的,当内存接近最大堆大小一段时间后,它会从内存中清除对象。我没有看到这个,因为我的电脑中有很多 RAM,但是使用 Xmx50m 我可以看到它按照你说的那样工作。谢谢。

标签: java sockets


【解决方案1】:

垃圾回收不是即时的,你有什么真正的内存问题吗?您是否尝试过以较低的-Xmx 值运行客户端,您是否收到了OutOfMemoryError? – user3707125

你是对的,当内存接近最大堆大小一段时间后,它会从内存中清除对象。我没有看到这个,因为我的电脑中有很多 RAM,但是使用 Xmx50m 我可以看到它按照你说的那样工作。 ——马特乌斯·维卡里

【讨论】:

    【解决方案2】:

    显然bombasListener.run(),不管它是什么,都没有发布提供的列表。

    NB ObjectInputStream.readObject() 不会在流结束时返回 null。因此,将此测试用作读取循环的终止条件是不正确的。

    【讨论】:

      猜你喜欢
      • 2020-04-16
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 2019-01-16
      • 2016-06-29
      • 1970-01-01
      • 2022-06-25
      相关资源
      最近更新 更多