2011-09-02 15 views
9

खाने के लिए मेरे पास एक जावा गेम सर्वर है जो 1 टीसीपी कनेक्शन प्रति थ्रेड का उपयोग करता है। (मुझे पता है कि यह बुरा है लेकिन मुझे इसे अभी इस तरह रखना होगा)। के बारे में 12 घंटे या उससे अधिक सर्वर के सक्रिय रहने की (और जुड़े 3.000 के बारे में खिलाड़ियों) के बादBufferedReader.read() 100% सीपीयू

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); 
    } 
} 

: एक (3.2GHz 6cor x2 मशीन, 24GB राम, विंडोज सर्वर 2003 64bits) और यहाँ पर कोड का एक टुकड़ा है जब तक मैं जावा एप्लिकेशन को मैन्युअल रूप से रीबूट नहीं करता, तब तक सर्वर सभी 12 CPUs का 100% हमेशा के लिए खाना शुरू करता है। तो खेल खराब बुराई शुरू होता है और मेरे खिलाड़ी शिकायत शुरू करते हैं।

Screenshot of my profiling result

इसलिए मैं अनुमान लगा रहा हूँ कि समस्या यहाँ से आ रहा है:

मैं आवेदन की रूपरेखा की कोशिश की और यहाँ है कि मैं क्या लेकर आए हैं

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

जानते हुए भी कि परिवर्तनीय "_in" सॉकेट इनपुट का एक पाठक है: (_in = नया BufferedReader (नया इनपुटस्ट्रीम रीडर (_socket.getInputStream()))।

पृथ्वी पर _in.read() लंबे सर्वर के बाद इतने सारे CPU क्यों लेते हैं?

मैंने थ्रेड.sleep (1) डालने का प्रयास किया है; और जबकि लूप के अंदर, लेकिन कुछ भी नहीं करता है, मुझे लगता है कि समस्या BufferedReader.read() विधि के अंदर है।

क्या किसी को यह पता है कि इसका क्या कारण हो सकता है ?? और इसे कैसे ठीक करें?

+6

मुझे आश्चर्य है कि यह इस तथ्य के बजाय है कि आप एक लूप में स्ट्रिंग कॉन्सटेनेशन का उपयोग कर रहे हैं। और * क्यों * आप एक समय में केवल एक ही चरित्र पढ़ रहे हैं? –

+0

पैकेट छोटे स्ट्रिंग्स हैं: "AB123"। तो इससे कोई फर्क नहीं पड़ता। – Reacen

+2

जब तक आप किसी पर डीडीओएस हमला शुरू नहीं करते हैं, तब तक आप एक बड़ी स्ट्रिंग भेजते हैं। स्ट्रिंगबिल्डर का उपयोग करने के लिए एकाधिक वर्णों और * * को पढ़ने में इतना आसान है ... ऐसा क्यों नहीं करते? –

उत्तर

1

मुझे नहीं पता कि कॉल धीमा क्यों है लेकिन मैं कभी भी एक बाइट लूप में एक बाइट नहीं पढ़ूंगा। कौन जानता है कि आंतरिक फ़ंक्शन के किस प्रकार का ओवरहेड है।

मैं वर्तमान में स्ट्रीम और पार्स में उपलब्ध सभी डेटा पढ़ता हूं। इसके लिए एक बफर और कुछ अतिरिक्त बहीखाता की आवश्यकता होगी लेकिन किसी भी स्ट्रीम से बाइट द्वारा बाइट पढ़ने से कहीं भी तेज़ होगा।

+0

क्या आप इसके लिए कोड का उदाहरण प्रदान कर सकते हैं? – Reacen

+0

जावा BufferedReader buffered (नाम है omen ...) और एक से एक समय में एक बाइट पढ़ने अपेक्षाकृत आम है। BufferedInputStream में इसे लपेटने के द्वारा फ़ाइलइनपुटस्ट्रीम बनाम सीधे पढ़ने पर आप प्रदर्शन अंतर का निरीक्षण कर सकते हैं। –

0

'TCP कनेक्शन प्रति 1 धागा' '3.000 के बारे में खिलाड़ियों से जुड़ा'

= 3,000 धागे ?!

मेरा अनुमान है: थ्रेड की अधिकतम मात्रा जो बार-बार एक बाइट प्रतिलिपि बना सकती है, लगभग 3.000 है। यह बहुत अजीब नहीं लगता है।

समाधान: कम धागे और एक बार में अधिक बाइट पढ़ें।

आप एक निष्पादक सेवा का उपयोग कर सकते हैं। जावाडोक में एक सरल उदाहरण है: http://download.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html

+0

क्या आप कृपया थ्रेड पूलिंग के बारे में कुछ आसान विषयों से लिंक कर सकते हैं या इस धागे की समस्या को कभी भी ठीक करेंगे? – Reacen

0

ऐसा लगता है कि आप कभी भी BufferedReader को बंद नहीं करते हैं, जब तक आप kickplayer() विधि में इसका प्रयास नहीं कर रहे हैं।

प्रत्येक पाठक आपके एहसास से बहुत लंबा रह सकता है।

+0

इसे कैसे बंद करें? – Reacen

+0

थोड़ी देर के बाद, या अंत में ब्लॉक के बाद _in.close() पर कॉल करें। – FacilityDerek

+0

IOExceptions को पकड़ें और सौदा करें। – FacilityDerek

3

यह आपके पिछले प्रश्न का डुप्लिकेट है: An infinite loop somewhere in my code। कृपया एक नया प्रश्न न खोलें, बल्कि संपादन कार्यों का उपयोग करें।

कहा जा रहा है कि 3000 धागे निश्चित रूप से बहुत अधिक हैं और अधिकतर संदर्भ स्विचिंग की अत्यधिक मात्रा का कारण बनेंगे। प्रत्येक कनेक्शन के लिए एक नया धागा शुरू करने के बजाय, जावा में गैर-अवरुद्ध आईओ सुविधाओं का उपयोग करने पर विचार करें। उदाहरण यहां पाए जा सकते हैं: http://download.oracle.com/javase/1.4.2/docs/guide/nio/example/index.html

0

मुझे विश्वास है कि मुझे एक ही समस्या का सामना करना पड़ा है, और मैं इसे जावा में एक बग होने का अनुमान लगा रहा हूं। मैंने अपना प्रश्न BufferedReader.read() eating 100% of CPU पर पोस्ट किया है - शायद कोई वहां जवाब देगा और इससे आपको भी मदद मिलेगी।

संबंधित मुद्दे