2011-09-02 30 views
9

Tôi có một máy chủ trò chơi JAVA sử dụng 1 luồng cho mỗi kết nối TCP. (Tôi biết nó xấu nhưng tôi sẽ phải giữ nó theo cách này bây giờ). Trên một (3.2GHz 6cor máy x2, RAM 24GB, Windows Server 2003 64bits) và đây là một phần của mã:BufferedReader.read() ăn 100% của 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); 
    } 
} 

Sau khoảng 12 giờ hoặc nhiều máy chủ thời gian hoạt động (và khoảng 3.000 người chơi kết nối) các máy chủ bắt đầu ăn 100% của tất cả 12 CPU cho đến khi tôi tự khởi động lại ứng dụng JAVA. Vì vậy, trò chơi bắt đầu tụt hậu verry xấu và người chơi của tôi bắt đầu phàn nàn.

Tôi đã thử profiling ứng dụng và đây là những gì tôi đã đưa ra:

Screenshot of my profiling result

Vì vậy, tôi đoán rằng vấn đề xuất phát từ đây:

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

biết rằng biến "_in" là một đầu đọc của đầu vào socket: (_in = new BufferedReader (new InputStreamReader (_socket.getInputStream()))).

Tại sao trên trái đất _in.read() mất quá nhiều CPU sau một thời gian chờ máy chủ dài?

Tôi đã thử đặt một Thread.sleep (1); và nhiều hơn nữa bên trong vòng lặp while, nhưng không làm bất cứ điều gì, tôi đoán vấn đề nằm bên trong phương thức BufferedReader.read().

Có ai có bất kỳ ý tưởng nào về điều gì có thể gây ra điều này không ?? Và làm thế nào để khắc phục nó?

+6

Tôi ngạc nhiên vì điều này thay vì thực tế là bạn đang sử dụng nối chuỗi trong một vòng lặp. Và * tại sao * bạn chỉ đọc một nhân vật duy nhất tại một thời điểm? –

+0

các gói là các chuỗi nhỏ verry như: "AB123". vì vậy nó không quan trọng. – Reacen

+2

Cho đến khi bạn kết thúc được gửi một chuỗi lớn bởi ai đó tung ra một cuộc tấn công DDOS vào bạn. Thật dễ dàng để đọc nhiều ký tự và * cũng * để sử dụng StringBuilder ... tại sao không làm như vậy? –

Trả lời

1

Tôi không biết tại sao cuộc gọi chậm nhưng tôi sẽ không bao giờ đọc một byte tại một thời điểm trong một vòng lặp chặt chẽ. Ai biết được loại chức năng nội bộ nào.

Tôi sẽ đọc tất cả dữ liệu hiện có trong luồng và phân tích cú pháp đó. Điều này sẽ yêu cầu một bộ đệm và một số sổ kế toán bổ sung nhưng anyway nhanh hơn so với đọc byte theo byte từ một dòng.

+0

Bạn có thể vui lòng cung cấp một ví dụ về mã cho điều đó không? – Reacen

+0

Java BufferedReader được đệm (nomen est omen ...) và đọc một byte tại một thời điểm từ một là tương đối phổ biến. Bạn có thể quan sát sự khác biệt hiệu năng khi đọc trực tiếp từ một FileInputStream và gói nó trong một BufferedInputStream. –

0

'1 thread mỗi kết nối TCP' 'khoảng 3.000 người chơi kết nối'

= 3,000 bài ?!

Đoán của tôi: số lượng chủ đề tối đa có thể sao chép liên tục một byte tại một thời điểm là khoảng 3.000. Điều đó không có vẻ kỳ lạ.

Giải pháp: ít chủ đề hơn và đọc nhiều byte hơn một lần.

Bạn có thể sử dụng một executorService. Có một ví dụ đơn giản trong javadoc: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

+0

Bạn có thể vui lòng liên kết tôi với một số chủ đề dễ dàng về phân luồng chuỗi hoặc những gì sẽ khắc phục được vấn đề này không? – Reacen

0

Dường như bạn chưa bao giờ đóng BufferedReader, trừ khi bạn đang thử nó trong phương thức kickPlayer().

Mỗi người đọc có thể sống lâu hơn bạn nhận ra.

+0

cách đóng nó? – Reacen

+0

Gọi _in.close() sau vòng lặp while hoặc trong khối cuối cùng. – FacilityDerek

+0

Bắt và đối phó với IOExceptions. – FacilityDerek

3

Đây là bản sao câu hỏi trước của bạn: An infinite loop somewhere in my code. Vui lòng không mở ra một câu hỏi mới, mà thay vào đó hãy sử dụng các chức năng chỉnh sửa.

Điều đó đang được nói, 3000 chủ đề chắc chắn là rất nhiều và rất có thể sẽ gây ra quá nhiều chuyển đổi ngữ cảnh. Thay vì bắt đầu một chuỗi mới cho mỗi kết nối, hãy xem xét sử dụng các cơ sở IO không chặn trong Java. Bạn có thể tìm thấy các ví dụ tại đây: http://download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html

0

Tôi tin rằng tôi đã gặp phải vấn đề tương tự và tôi đoán đó là lỗi trong Java. Tôi đã đăng câu hỏi của tôi tại BufferedReader.read() eating 100% of CPU - có thể ai đó sẽ đưa ra câu trả lời ở đó và điều đó cũng sẽ giúp bạn.

Các vấn đề liên quan