我有一个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应用程序。因此,游戏开始落后于糟糕,我的玩家开始抱怨。
我尝试过分析应用程序,这就是我想出的:
所以我猜这个问题来自这里:
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()方法内部。
有没有人知道会导致什么?以及如何解决它?
答案 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