我代码中的某个无限循环

我有这个Java游戏服务器,可以处理多达3,000个tcp连接,每个播放器,或者每个tcp连接都有自己的线程,每个线程都是这样的:

public void run() { try { String packet = ""; char charCur[] = new char[1]; while(_in.read(charCur, 0, 1)!=-1 && MainServer.isRunning) { if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r') { packet += charCur[0]; }else if(!packet.isEmpty()) { parsePlayerPacket(packet); packet = ""; } } kickPlayer(); }catch(IOException e) { kickPlayer(); }catch(Exception e) { kickPlayer(); } finally { try{ kickPlayer(); }catch(Exception e){}; MainServer.removeIP(ip); } } 

代码运行良好,我知道每个玩家的每个线程都是一个坏主意,但我现在也会这样保持这种方式。 服务器在快速机器上运行良好(6cor x2,64bits,24GB RAM,Windows Server 2003)。

但是在某些时候,在大约12个小时的UpTime之后,服务器开始在某个地方循环…我知道因为java进程无限地占用了99%的CPU,直到下次重启。 而且我很难分析应用程序,因为我不想打扰玩家。 我使用的探查器(visualvm)总是最终破坏服务器而不告诉我哪里出了问题。

无论如何,在上面那段代码中我想可能问题来自于:

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

_in是客户端套接字的BufferedReader )。

是否有可能_in.read()可以无限地返回其他东西,这将使我的代码运行并占用99%的资源? 我的代码有问题吗? 我不明白一切,我只写了一半。

一次读取一个char几乎和使用+ =构建String一样慢。 我无法告诉你哪个更糟糕。 如果单个连接使用这种方法捆绑整个核心,我不会感到惊讶。

最简单的“修复”是使用BufferedReader和StringBuilder。

然而,读取数据的最有效方法是将字节读入ByteBuffer并解析“行”。 我假设您正在接收ASCII文本。 您可以编写解析器,以便能够在一个阶段处理内容和行尾(即一次传递数据)

使用最后一种方法,这里是我从套接字解析XML消息并以XML回复的示例(包括代码)。 典型的延迟为16微秒,吞吐量为每秒264K。

http://vanillajava.blogspot.com/2011/07/send-xml-over-socket-fast.html


你可以做类似以下的事情,这些事情可能足够快

 BufferedReader br = new BufferedReader(_in); for(String line; ((line = br.readline()) != null;) { if(line.indexOf('\0') >= 0) for(String part: line.split("\0")) parsePlayerPacket(part); else parsePlayerPacket(line); } 

如果你发现这个解决方案很简单并且熟悉ByteBuffer,你可以考虑使用它们。

我在我写的一个应用程序中遇到了同样的问题。 我的应用程序占用了50%的CPU(双核)。

然后我做了解决问题的方法,就是让线程睡1个时间戳

 Thread.sleep(1); 

我希望这对你有所帮助

编辑:

哦,那是什么?
}catch(IOException e)
{
kickPlayer();
}catch(Exception e)
{
kickPlayer();
}

我认为你不需要IOException Catch(exception捕获,捕获各种exception)

那种exception处理只是伤害了我的眼睛。 因为你最后再次调用它,所以在catch块中调用kickPlayer()是没有意义的。 最后执行(几乎)总是。

现在关于你的问题,忘记我之前的回答,我有点睡着了XD。 在发布的while循环中,我没有看到任何容易循环的东西。 当没有更多数据或抛出exception时,InputStream.read()返回-1。 问题必须在其他代码中,或者可能是线程问题。

正如他们在其他答案中告诉你的那样,尝试使用缓冲流,一次只读取一个字符块而不是一个字符,并替换StringBuilder的append方法的字符串连接。 这应该可以提高性能,但不确定它是否能解决问题(可能会在24小时而不是12小时内出现)。