I have a JAVA game server that uses 1 thread per TCP connection. (I know it's bad but i'll have to keep it this way for now). On a (3.2Ghz 6cor x2 machine, 24GB RAM, windows server 2003 64bits) and here is a piece of the code:
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);
}
}
After about 12 hours or more of server upTime (and about 3.000 players connected) the server starts eating 100% of all the 12 CPUs for ever, until I manually reboot the JAVA application. So the game starts lagging verry bad and my players starts complaining.
I have tried profiling the application and here is what I came up with:
So I am guessing that the problem is coming from here:
while(_in.read(charCur, 0, 1)!=-1 && Server.isRunning)
knowing that the variable "_in" is a reader of the socket input : (_in = new BufferedReader(new InputStreamReader(_socket.getInputS开发者_JAVA百科tream()))).
Why on earth _in.read() takes so much CPU after a long server upTime?
I have tried putting a Thread.sleep(1); and more inside the While loop, but doesn't do anything, I guess the problem is inside of the BufferedReader.read() method.
Does anyone have any idea of what can cause this?? And how to fix it?
This is a duplicate of your previous question: An infinite loop somewhere in my code. Please do not open up a new question, but instead use the editing functions.
That being said, 3000 threads is definitely a lot and would most likely cause excessive amounts of context switching. Instead of starting a new thread for each connection, consider using non-blocking IO facilities in Java. Examples can be found here: http://download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html
I don't know why the call is slow but I would never read one byte at a time in a tight loop. Who knows what kind of overhead the internal function has.
I would read all the data that is available currently in the stream and parse that. This would require a buffer and some extra bookkeeping but anyway faster than reading byte by byte from a stream.
'1 thread per TCP connection' 'about 3.000 players connected'
= 3.000 threads?!
My guess: the maximum amount of threads that can repeatedly copy one byte at a time is around 3.000. That doesn't sound so weird.
Solution: less threads and read more bytes in one go.
You could use a executorService. There is a simplistic example in the javadoc: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
It doesn't look like you ever close the BufferedReader either, unless you are attempting it in the kickPlayer() method.
Each reader may be living a lot longer than you realise.
I'm also stuck on this same problem, I have also tried many solutions but no luck with read(byte). But when I have tried with readLine(), it works well. @Reacen did you found any other answer please let me know too.
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;
}
精彩评论