【问题标题】:java socket Object memory leakjava socket对象内存泄漏
【发布时间】:2012-09-12 15:16:51
【问题描述】:

我在 java Socket Object 通信中遇到了内存泄漏问题。

这是我的发送线程。

    // create a new thread to send the packet
@Override
public synchronized void run() {

    if(!genericSocket.isConnected()){
        if(logger.isEnabled())
            logger.logMessage(PFLogging.LEVEL_WARN, "Socket is close");
        return;
    }

    int retry = 0;
    boolean packetSent = false;

    synchronized (objWriter) {
        while ((retry < RETRY) && (!packetSent) && (genericSocket.isConnected())) {
            try {
                objWriter.writeObject(bean);

                objWriter.flush();



                // Try until the cache is reset and the memory is free
                /*
                boolean resetDone = false;
                while(!resetDone) {
                    try {
                        objWriter.reset();
                        resetDone = true;
                    } catch (IOException r) {
                        Thread.sleep(1);
                    }
                }
                */

                // No error and packet sent
                continuousError = 0;
                packetSent = true;
            } catch (Exception e) {
                continuousError++;

                if(logger.isEnabled())
                    logger.logMessage(PFLogging.LEVEL_ERROR, "Continuous Error [" + continuousError + "] sending message [" + e.getMessage() + "," + e.getCause() + "]");

                // control the number of continuous errors
                if(continuousError >= CONTINUOUS_ERROR) {
                    if(logger.isEnabled())
                        logger.logMessage(PFLogging.LEVEL_WARN, "I close the socket");
                    genericSocket.disconnect();
                }

                // next time is the time!
                retry++;
            }
        }
    }
}

缓存,当我每毫秒发送大约 i 个数据包时,它会不断增长!

如果我添加注释部分,缓存是干净的,但是当我需要发送异步长消息(大约 3000 个字符)时,我看到另一条消息丢失了!

还有另一种方法可以在不重置缓存的情况下清理缓存??

【问题讨论】:

    标签: java sockets stream memory-leaks objectoutputstream


    【解决方案1】:

    ObjectOutputStream.reset() 是无法避免的,因为它是清除本地哈希表的唯一方法,您可以参考 ObjectOutputStream 的 java 源代码了解 reset() 中发生的详细信息,否则您最终会得到 OutOfMemoryError

    但是你可以很好地实现像

    这样的功能
    private void writeObject(Object obj, ObjectOutputStream oos) throws IOException
        {
            synchronized(oos)
            {
                oos.writeObject(obj);
                oos.flush();
                oos.reset();
            }
        }
    

    但是,您必须确保对 ObjectOutputStream 的所有写入都通过此方法进行。

    【讨论】:

      【解决方案2】:

      我找到的唯一解决方案是,首先启动发送线程,检查线程池是否为空,在这种情况下我重置输出流。 我整晚都在运行这个软件来检查这个。

      谢谢大家!

      马特奥

      【讨论】:

        【解决方案3】:

        我会定期使用ObjectOutputStream.reset() 来清除流的对象缓存。

        您甚至可以在发送每个对象后使用它。 ;)

        【讨论】:

        • 我现在但是如果我重置缓冲区,很多情况下我会丢失数据包(此套接字用于异步和同步消息)
        • @MatteoGatto reset() 不会导致丢包。
        • @MatteoGatto 会导致您多次发送同一个对象。流的一个常见错误是通过两个不同的流(例如 ObjectOutputStream 和 PrintWriter)或两个 ObjectOutputStream 进行写入或读取。这将导致数据损坏。
        【解决方案4】:

        ciao :),

        在 ObjectOutputStream.flush() 之后,您可以安全地使用 ObjectOutputStream.reset()

        除非您在另一个线程中使用 objWriter somwhere 而不使用同步 (objWriter) 语句。 在这种情况下,恕我直言,最好的方法是在线程中使用 objWriter,它将从另一个线程填充的同步队列(参见队列子类http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Queue.html,例如http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ConcurrentLinkedQueue.html)发送对象(记住使用 object.clone(),因为 objcet 本身没有同步,它可以在你编写它或在队列中被其他线程修改!如果你克隆它,你的克隆将是一个安全副本。

        这样你就不需要同步语句了,因为线程和 ObjectOutputStream 之间的数据流已经同步了,你会更不容易出错

        【讨论】:

        • 好的,谢谢,我看到没有同步通信会更快,但原来的问题总是在这里 :)
        • 我的代码也许你正在优化,但首先你让你的代码更不容易出错。
        猜你喜欢
        • 1970-01-01
        • 2014-06-22
        • 2019-02-13
        • 2012-10-31
        • 2011-04-17
        • 2011-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多