2011-09-02 79 views
9

我有一個JAVA遊戲服務器,每個TCP連接使用1個線程。 (我知道這很糟糕,但現在我必須保持這種狀態)。上的(3.2Ghz的6cor X2機,24GB RAM,Windows Server 2003和的64位),並在這裏是一塊代碼:BufferedReader.read()吃了100%的CPU

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玩家連接)後,將服務器開始吃掉所有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())))。

爲什麼在長時間的服務器uptime之後,_in.read()需要很多CPU?

我試過把Thread.sleep(1);和更多內部的循環,但沒有做任何事情,我猜這個問題是在BufferedReader.read()方法中。

有沒有人有什麼可以導致這種情況?以及如何解決它?

+6

我很驚訝它的這個,而不是事實,你使用字符串連接在一個循環。 *爲什麼*你一次只能讀一個字符? –

+0

數據包非常小,例如:「AB123」。所以沒關係。 – Reacen

+2

直到你最終被髮送一個巨大的字符串被某人發動DDOS攻擊。讀取多個字符和*還可以使用StringBuilder非常簡單...爲什麼不這樣做呢? –

回答

1

我不知道爲什麼這個調用很慢,但我永遠不會在嚴格的循環中一次讀取一個字節。誰知道內部函數有什麼樣的開銷。

我會讀取當前流中可用的所有數據並解析該數據。 這需要一個緩衝區和一些額外的簿記,但無論如何都比從流中逐字節讀取更快。

+0

你能否提供一個代碼示例? – Reacen

+0

Java BufferedReader被緩衝(nomen est omen ...)並且每次從一個字節讀取一個字節比較常見。當直接從FileInputStream中讀取並將其包裝到BufferedInputStream中時,您可以觀察性能差異。 –

0

'1個每個TCP連接線程' '約3.000玩家' 連接

= 3.000線程?

我的猜測:一次可以重複複製一個字節的線程的最大數量約爲3.000。這聽起來不太奇怪。

解決方案:減少線程數量,一次讀取更多字節。

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

+0

請問我可以把我和一些關於線程池的簡單話題聯繫起來,或者有什麼可以解決這個線程問題? – Reacen

0

它看起來並不像你曾經關閉過BufferedReader,除非你正在kickPlayer()方法中嘗試它。

每個讀者可能比你意識到的生活時間長很多。

+0

如何關閉它? – Reacen

+0

在while循環之後或在finally塊中調用_in.close()。 – FacilityDerek

+0

捕獲並處理IOExceptions。 – FacilityDerek

0

我相信我是來面臨着同樣的問題,我猜它是Java中的錯誤。我在BufferedReader.read() eating 100% of CPU發佈了我的問題 - 也許有人會在那裏給出答案,這也會對你有所幫助。