2011-09-02 14 views
9

Ho un server di gioco JAVA che utilizza 1 thread per connessione TCP. (So ​​che è male ma dovrò tenerlo così per ora). Su una (macchina 3.2Ghz 6cor x2, RAM 24GB, Windows Server 2003 64bit) e qui è un pezzo di codice:BufferedReader.read() mangia il 100% della 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); 
    } 
} 

Dopo circa 12 ore o più di uptime del server (e circa 3.000 giocatori collegati) il il server inizia a mangiare il 100% di tutte le 12 CPU per sempre, fino a quando non riavvio manualmente l'applicazione JAVA. In questo modo il gioco inizia a rallentare e i miei giocatori iniziano a lamentarsi.

Ho provato profiling l'applicazione e qui è quello che mi si avvicinò con:

Screenshot of my profiling result

Così sto indovinando che il problema viene da qui:

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

sapendo che il variabile "_in" è un lettore dell'ingresso socket: (_in = new BufferedReader (new InputStreamReader (_socket.getInputStream())))).

Perché on-_y.read() richiede così tanta CPU dopo un lungo server upTime?

Ho provato a mettere un Thread.sleep (1); e più all'interno del ciclo While, ma non fa nulla, immagino che il problema sia all'interno del metodo BufferedReader.read().

Qualcuno ha qualche idea di cosa può causare questo ?? E come ripararlo?

+6

Sono sorpreso che sia questo piuttosto che il fatto che si sta utilizzando la concatenazione di stringhe in un ciclo. E * perché * stai leggendo solo un singolo personaggio alla volta? –

+0

i pacchetti sono stringhe molto piccole come: "AB123". quindi non importa. – Reacen

+2

Fino a quando non viene inviata una stringa enorme da qualcuno che lancia un attacco DDOS su di te. È così facile leggere più caratteri e * anche * usare StringBuilder ... perché non farlo? –

risposta

1

Non so perché la chiamata è lenta, ma non avrei mai letto un byte alla volta in un circuito chiuso. Chissà che tipo di sovraccarico ha la funzione interna.

Vorrei leggere tutti i dati attualmente disponibili nello stream e analizzarli. Ciò richiederebbe un buffer e un po 'di contabilità aggiuntiva, ma comunque più veloce della lettura byte per byte da un flusso.

+0

Puoi per favore fornire un esempio di codice per questo? – Reacen

+0

Java BufferedReader è memorizzato nel buffer (nomen est omen ...) e la lettura di un byte alla volta da uno è relativamente comune. È possibile osservare la differenza di prestazioni quando si legge direttamente da FileInputStream e lo si avvolge in un BufferedInputStream. –

0

'1 thread per connessione TCP' 'circa 3.000 giocatori collegato'

= 3.000 discussioni ?!

La mia ipotesi: la quantità massima di thread che è possibile copiare ripetutamente un byte alla volta è di circa 3.000. Non sembra così strano.

Soluzione: meno thread e leggere più byte in una volta.

È possibile utilizzare un executorService. C'è un esempio semplicistico in javadoc: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

+0

Puoi per favore collegarmi ad alcuni semplici argomenti sul pooling dei thread o quale sarà il problema? – Reacen

0

Non sembra che tu abbia mai chiuso BufferedReader, a meno che non lo stia provando nel metodo kickPlayer().

Ogni lettore potrebbe vivere molto più a lungo di quanto tu creda.

+0

come chiuderlo? – Reacen

+0

Chiama _in.close() dopo il ciclo while o nel blocco finally. – FacilityDerek

+0

Catch and deal with IOExceptions. – FacilityDerek

3

Questo è un duplicato della domanda precedente: An infinite loop somewhere in my code. Si prega di non aprire una nuova domanda, ma utilizzare invece le funzioni di modifica.

Detto questo, 3000 thread sono sicuramente molto e molto probabilmente causerebbero eccessive conversioni di contesto. Invece di iniziare una nuova discussione per ogni connessione, considera l'utilizzo di strutture IO non bloccanti in Java. Gli esempi possono essere trovati qui: http://download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html

0

Credo di essere venuto di fronte allo stesso problema, e credo che sia un bug in Java. Ho postato la mia domanda al BufferedReader.read() eating 100% of CPU - forse qualcuno darà una risposta e questo aiuterà anche te.

Problemi correlati