BufferedReader.read()占用100%的CPU

时间:2011-09-02 09:12:57

标签: java multithreading sockets tcp profiling

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

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

服务器upTime大约12小时或更长时间(连接大约3.000个播放器)后,服务器开始永久占用所有12个CPU的100%,直到我手动重启JAVA应用程序。因此,游戏开始落后于糟糕,我的玩家开始抱怨。

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

Screenshot of my profiling result

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

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

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

为什么地球上_in.read()在长时间服务器upTime之后占用了这么多CPU?

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

有没有人知道会导致什么?以及如何解决它?

5 个答案:

答案 0 :(得分:3)

这与您之前的问题重复:An infinite loop somewhere in my code。请不要打开新问题,而是使用编辑功能。

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

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

  

'每个TCP连接1个线程'   '约有3000名球员连接'

= 3.000个帖子?!

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

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

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

答案 3 :(得分:0)

看起来你不会关闭BufferedReader,除非你在kickPlayer()方法中尝试它。

每个读者的生活时间可能比你意识到的要长很多。

答案 4 :(得分:0)

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

Function Remove(Str As String) As String
    Dim xChars As String
    Dim I As Long
    xChars = "/.',_#$%@!()^*&"
    For I = 1 To Len(xChars)
        Str = Replace$(Str, Mid$(xChars, I, 1), "")
    Next
    Remove = Str
End Function