简体   繁体   English

来自Inputstream的Java readObject占用CPU的50%

[英]Java readObject from Inputstream taking up 50% of CPU

I am running into a weird problem where this thread which reads from an inputstream, specifically readObject. 我遇到一个奇怪的问题,这个线程从输入流读取,特别是readObject。 The thread is blocking on the call like it is suppose to because I have tried putting log debugging statements and it shows its blocking. 该线程在调用时阻塞,因为我试图将日志调试语句放入并显示其阻塞。 The problem is this thread is still marked as running in the profiler and it takes up 50% of my cpu usage. 问题是这个线程仍然标记为在探查器中运行,它占用了我的CPU使用率的50%。 I have a similar thread to this which blocks properly and when blocked takes up 0% cpu. 我有一个类似的线程,它正确阻塞,当阻塞占用0%的CPU。 I am baffled at what can be going wrong here. 我对这里可能出现的问题感到困惑。

Since I am a new user I can't post image, please see. 由于我是新用户,我无法发布图片,请参阅。 Green in the image means running, yellow is blocked or waiting. 图像中的绿色表示运行,黄色被阻止或等待。

http://i.imgur.com/5FPyZ.png Image also available unscaled here : 图片也可在此处展开

Main 主要

  {
    SocketFactory factory = SocketFactory.getDefault();
    Socket tcpSocket = factory.createSocket("localhost", 5011);
    IoTcpReadRunnable ioTcpReadRunnable = new IoTcpReadRunnable(new MessageProcessor()
    {
        @Override
        public void enqueueReceivedMessage(Object message)
        {
            System.out.println("MessageReceived Enqueued.");
        }

        @Override
        public void enqueueMessageToWrite(Envelope message)
        {
            System.out.println("Message Enqueued to Write.");
        }
    }, tcpSocket);

    new Thread(ioTcpReadRunnable, "ClientExample IoTcpRead").start(); 

} }

TcpRead Runnable TcpRead Runnable

public final class IoTcpReadRunnable implements Runnable {
public static final Logger logger = LoggerFactory.getLogger(IoTcpReadRunnable.class);
protected MessageProcessor<MessageType> messageProcessor = null;
protected Socket tcpSocket = null;
protected ObjectOutputStream outputStream = null;
protected ObjectInputStream inputStream = null;
protected boolean connected = false;

public IoTcpReadRunnable(MessageProcessor<MessageType> messageProcessor, Socket tcpSocket)
{
    this.messageProcessor = messageProcessor;
    this.tcpSocket = tcpSocket;
    this.init();
}

protected void init()
{
    try
    {
        this.outputStream = new ObjectOutputStream(tcpSocket.getOutputStream());
        this.outputStream.flush();

        this.inputStream = new ObjectInputStream(tcpSocket.getInputStream());
    }
    catch (IOException ex)
    {
        logger.error("Tcp Socket Init Error Error ", ex);
    }

}

public boolean isConnected()
{
    return connected;
}

protected synchronized Object readObject() throws IOException, ClassNotFoundException
{
    Object readObject = null;
    //blocks here
    logger.trace("{} About to block for read Object");

    readObject = this.inputStream.readObject();
    logger.trace("{} Read Object from Stream: {} ", "", readObject);

    return readObject;
}

public void close()
{
    try
    {
        //todo
        this.connected = false;
        this.outputStream.flush();
        this.outputStream.close();
        this.inputStream.close();
        synchronized (tcpSocket)
        {
            this.tcpSocket.close();
        }
    }
    catch (IOException ex)
    {
        logger.error("Error closing Socket");
    }
}

@Override
public void run()
{

    this.connected = true;

    while (this.connected)
    {
        try
        {
            Object readObject = readObject();

            if (readObject != null)
            {
                this.messageProcessor.enqueueReceivedMessage((MessageType) readObject);
            }
            else
            {
                logger.error("Read Object is null");
            }
        }
        catch (IOException ex)
        {
            logger.error("TcpRecieveThread IOException", ex);
        }
        catch (ClassNotFoundException ex)
        {
            logger.error("TcpRecieveThread ClassnotFound", ex);
        }
    }
    this.close();

}
}
  1. Profile it. 简介它。 That is likely to tell you a lot. 这可能会告诉你很多。

  2. Yes - serializing and deserializing objects using Java ObjectIOStreams is relatively CPU intensive. 是 - 使用Java ObjectIOStreams序列化和反序列化对象相对CPU密集型的。

  3. You don't appear to be using BufferedInputStream / BufferedOutputStream in your IO pipelines, so it is quite possible that data is being read and written one byte at a time. 您似乎没有在IO管道中使用BufferedInputStream / BufferedOutputStream,因此很可能一次一个字节地读取和写入数据。 That is likely to increase your CPU usage dramatically. 这可能会大大增加您的CPU使用率。


I am saying this thread should be blocked and taking up 0% of cpu when ReadObject is called. 我说这个线程应该被阻塞,并在调用ReadObject时占用0%的cpu。

I think you are fundamentally misunderstanding how I/O in general and readObject in particular works. 我认为你从根本上误解了一般的I / O和特定的readObject是如何工作的。 When you call the method, it makes one (or possibly many) system calls to fetch bytes from the socket. 当您调用该方法时,它会进行一次(或可能很多次)系统调用以从套接字中获取字节。 Then, it decodes those bytes to figure out what objects need to be created, and then creates and initializes them. 然后,它解码这些字节以找出需要创建的对象,然后创建并初始化它们。 All of this work takes CPU time that is accounted to process as "user time" or "system time". 所有这些工作都将占用的CPU时间视为“用户时间”或“系统时间”。 The only time when the CPU is not being accounted to the process is when / if a read syscall has to wait for a network packet to arrive. CPU没有被计入进程的唯一时间是read /系统调用必须等待网络数据包到达的时间。

I also don't believe those "profiling" results. 我也不相信那些“剖析”结果。 For a start, a straight-forward reading of your code says that the main method creates a new thread, starts it and then immediately returns. 首先,直接读取代码表示main方法创建一个新线程,启动它然后立即返回。 Yet those results seem to be saying that the "main" thread is running continuously. 然而,这些结果似乎在说“主”线程在不断运行。 That is nonsensical ... and calls into doubt the methodology you are using to do the profiling and/or the way you are interpreting them to us. 这是荒谬的......并且怀疑您用于分析的方法和/或您向我们解释它们的方式。


One more thing to check. 还有一件事需要检查。 Have you looked at the log file? 你看过日志文件了吗? Is the logging is correctly configured? 日志记录是否正确配置?

May be you can look at this way in order to improve it. 也许你可以通过这种方式来改进它。

  1. Try using custom writeObject and readObject() 尝试使用自定义writeObject和readObject()

  2. Try Google Protocol Buffers 试试Google Protocol Buffers

  3. Compressing the stream 压缩流

  4. When you serialize an object, provide serialization only for the required attributes.Do not serialize entire object.So use transient. 序列化对象时,仅为所需属性提供序列化。不要序列化整个对象。因此使用瞬态。

Worth looking this discussion: Java Object Serialization Performance tips 值得一看这个讨论: Java对象序列化性能提示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM