繁体   English   中英

BufferedReader.read() 占用了 100% 的 CPU

[英]BufferedReader.read() eating 100% of CPU

我有一个 JAVA 游戏服务器,每个 TCP 连接使用 1 个线程。 (我知道这很糟糕,但我现在必须保持这种状态)。 在(3.2Ghz 6cor x2 机器,24GB RAM,windows server 2003 64bits)上,这是一段代码:

public void run()
{
    try
    {   
        String packet = "";
        char charCur[] = new char[1];

        while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
        {
            if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
            {
                packet += charCur[0];
            }else if(!packet.isEmpty())
            {
                parsePlayerPacket(packet);
                packet = "";
            }
        }

    }catch(Exception e)
    {
        e.printStackTrace();
    }
    finally
    {
        try{
            kickPlayer();
        }catch(Exception e){e.printStackTrace();};

        Server.removeIp(_ip);
    }
}

在大约 12 小时或更长时间的服务器正常运行时间(并且连接了大约 3.000 个玩家)之后,服务器开始消耗 100% 的所有 12 个 CPU,直到我手动重新启动 JAVA 应用程序。 所以游戏开始非常糟糕,我的球员开始抱怨。

我试过分析应用程序,这是我想出的:

我的分析结果的屏幕截图

所以我猜测问题来自这里:

while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)

知道变量“_in”是套接字输入的读取器:(_in = new BufferedReader(new InputStreamReader(_socket.getInputStream())))。

为什么 _in.read() 在长时间的服务器正常运行后占用这么多 CPU?

我试过放一个 Thread.sleep(1); 在 While 循环中还有更多,但没有做任何事情,我猜问题出在 BufferedReader.read() 方法内部。

有没有人知道是什么导致了这个? 以及如何修复它?

这是您上一个问题的重复: 我的代码中某处的无限循环 请不要打开新问题,而是使用编辑功能。

话虽如此,3000 个线程肯定很多,而且很可能会导致过多的上下文切换。 考虑在 Java 中使用非阻塞 IO 设施,而不是为每个连接启动一个新线程。 示例可以在这里找到: http : //download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html

我不知道为什么调用很慢,但我永远不会在紧密循环中一次读取一个字节。 谁知道内部函数有什么样的开销。

我会读取流中当前可用的所有数据并对其进行解析。 这将需要一个缓冲区和一些额外的簿记,但无论如何比从流中逐字节读取要快。

我也遇到了同样的问题,我也尝试了很多解决方案,但read(byte)没有运气。 但是当我尝试使用readLine() 时,它运行良好。 @Reacen您是否找到了任何其他答案,也请告诉我。

            public void run() {
            try {
                InputStream input = clientSocket.getInputStream();
                BufferedReader bf = new BufferedReader(new InputStreamReader(input));

                while (isRunning) {
                    if (mainServer.isStopped()) {
                        disconnect();
                    }
                    if (clientSocket.isClosed()) {
                        isRunning = false;
                        break;
                    }

                    // New Code Receive commands from device
                    String result = null;
                    try {
                        result = bf.readLine();
                        if (result == null) {
                            disconnect();
                        } else {
                            Pattern pattern = Pattern.compile("(?<=\\[).*(?=\\])");
                            Matcher matcher = pattern.matcher(result);
                            if (matcher.find()) {
                                result = matcher.group(0);
                            }
                        }
                    } catch (SocketTimeoutException e) {
                        logger.debug("Socket Read Timeout: " + remoteAddress);
                    } catch (SocketException e) {
                        isRunning = false;
                        break;
                    }
                    if (result == null || result.trim().length() == 0) {
                        continue;
                    }

“每个 TCP 连接 1 个线程”“连接了大约 3.000 个玩家”

= 3.000 个线程?!

我的猜测:一次可以重复复制一个字节的最大线程数约为 3.000。 这听起来并不奇怪。

解决方案:减少线程并一次性读取更多字节。

您可以使用 executorService。 javadoc中有一个简单的例子: http : //download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

看起来您也从未关闭过 BufferedReader,除非您在 kickPlayer() 方法中尝试它。

每个读者的寿命可能比您意识到的要长得多。

暂无
暂无

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

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