2010-07-16 23 views
5

में रेल पर जेआरबी के साथ पर्मजेन समस्या को ट्रैक करें हम टोमकैट के तहत चल रहे रेल पर जेआरबीई लिखे गए एक छोटे से वेब एप्लिकेशन चला रहे हैं। हम एक स्प्रिंग बैक-एंड का उपयोग कर रहे हैं जिसे किसी अन्य उत्पादन वेब एप्लिकेशन के साथ साझा किया गया है। दुर्भाग्य से, हम PermGen समस्याओं में चलते रहते हैं।टॉमकैट

ओएस: उबंटू लिनक्स 2.6.24-24-सर्वर # 1 SMP x86_64 जीएनयू/लिनक्स जावा: 1.6.0_21 बिलाव: 6.0.28 JRuby: 1.5.0 रेल: 2.3.7

वर्तमान में हम Google, याहू और Baidu द्वारा क्रॉल हो रहे हैं, इसलिए साइट का उपयोग बढ़ रहा है। मैं जेकोनसोल के साथ टोमकैट की निगरानी कर रहा हूं और हमें निश्चित रूप से कक्षाओं की अत्यधिक संख्या में समस्या दिखाई दे रही है। जब टोमकैट लॉन्च होता है, तो हमारे पास लगभग 12,000 वर्ग लोड होते हैं। 8 घंटों के बाद, हमारे पास लगभग 75,000 वर्ग लोड होते हैं। पर्मगेन एक ही समय में 100 एमबी से 460 एमबी तक चला जाता है।

कक्षा अनलोडिंग काम कर रही है, लेकिन यह केवल उसी 8 घंटे की अवधि में ~ 500 कक्षाएं उतार दी गई है। पर्मजेन कभी इकट्ठा नहीं होता है।

हम बिलाव के लिए निम्नलिखित वीएम विकल्पों के साथ चला रहे हैं:

-Xms2048m -Xmx2048m -XX:MaxPermSize=512m -XX:PermSize=128m \ 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 \ 
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled 

जाहिर है रिसाव किसी तरह का है। सवाल यह है कि कैसे? इस बारे में कोई सलाह है कि किसके लिए और किसके लिए ज़िम्मेदार है? मुझे आशा है कि यह हमारे हिस्से पर कुछ सचमुच मूर्खतापूर्ण गलती है, लेकिन मुझे यकीन नहीं है कि कहां से शुरू किया जाए।

किसी भी सलाह की सराहना की जाएगी।

संपादित

ऐसा लगता है कि हम एक नया हर एक आने वाली अनुरोध के लिए बनाया वर्ग देख रहे हैं।

संपादित 2

यह निश्चित रूप से JRuby से संबंधित है। जेकनसोल का उपयोग करके, मैंने कक्षा लोडर के लिए वर्बोज़ मोड सक्षम किया। यहाँ catalina.out से एक नमूना है:

[Loaded anon_class1275113147_895127379 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar] 
[Loaded anon_class1354333392_895127376 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar] 
[Loaded anon_class1402528430_895127373 from file:/opt/apache-tomcat-6.0.28/webapps/notes/WEB-INF/lib/jruby-core-1.5.0.jar] 

तो सवाल यह है कि कैसे मैं पार्टी उन अतिरिक्त कक्षाएं बनाने के लिए जिम्मेदार नीचे ट्रैक करते हैं हो जाता है?

संपादित 3

सुनिश्चित नहीं हैं कि इस समस्या है, लेकिन किसी भी तरह हम वर्ग लोडर के एक पागल संख्या के साथ समाप्त कर रहे हैं। jmap -permstat PID भाग गया और मिल गया:

class_loader classes bytes  parent_loader alive?    type 
total = 1320 135748 947431296 N/A    alive=1, dead=1319 N/A 

कि एक छोटे से अत्यधिक लगती है। बहुमत तीन प्रकार के क्लासलोडर्स में से एक हैं: sun.reflect.DelegatingClassLoader, org.jruby.util.JRubyClassLoader या org.jruby.util.ClassCache$OneShotClassLoader। फिर, jmap -permstat से उत्पादन नमूना:

class_loader   classes bytes  parent_loader   alive? type 
0x00007f71f4e93d58  1  3128  0x00007f71f4d54680  dead sun/reflect/[email protected] 
0x00007f721e51e2a0  57103 316038936 0x00007f720431c958  dead org/jruby/util/[email protected] 
0x00007f72182f2b10  4  12944  0x00007f721d7f3030  dead org/jruby/util/[email protected]72f2fd1158 
0x00007f721d7d50d8  9  457520  0x00007f720431c958  dead org/jruby/util/[email protected] 

उत्तर

6

PermGen निश्चित रूप से JRuby- आधारित अनुप्रयोगों में एक समस्या है। मुझे आश्चर्य नहीं है कि सीएमएस ज्यादा एकत्र नहीं कर रहा है। आम तौर पर एक वास्तविक स्मृति रिसाव नहीं है, बल्कि आवेदन परमिटन पर भारी और कठिन है और अभी तक इसका स्तर नहीं है।

मैं कुछ विकल्प प्रदान करते हैं कर सकते हैं: अगर आप लेवलिंग-ऑफ प्वाइंट पा सकते हैं

  1. टक्कर ऊपर आगे भी permgen को देखने के लिए।
  2. देखें कि क्या आप शुद्ध-व्याख्या मोड (-Djruby.compile.mode = OFF) में अपना एप्लिकेशन चलाने से दूर हो सकते हैं। यह आपके परमिट को भरने वाले वर्गों के एक बड़े हिस्से से छुटकारा पाना चाहिए।
  3. रेल 2.2 और अधिक threadsafe! मोड के साथ चलाने का प्रयास करें। एक रनटाइम में अपना एप्लिकेशन चलाना बड़ी मेमोरी बचत हासिल करने का एक और तरीका है, और यह परमजन पर भी लागू होता है।

संपादित करें: एफवाईआई, यह प्रश्न a JRuby bug हो गया। 1.5.2 और 1.6 रिलीज को इस विशेष मुद्दे को ठीक करना चाहिए। मेरी टिप्पणियां अभी भी सामान्य रूप से खड़ी हैं।

+0

4 उदाहरणों के लिए 75,000 कक्षाएं अभी भी मेरे लिए बहुत कुछ लगती हैं ... :) लेकिन मैं निश्चित रूप से कुछ और परीक्षण करूँगा। धन्यवाद! – organicveggie

+0

जो चीज मुझसे चिंतित है वह यह है कि ऐसा लगता है कि हर नए अनुरोध से नई कक्षाएं बनती हैं जो कभी जारी नहीं होतीं। यह सिर्फ मुझे सही नहीं लगता है। मैं समझता हूं कि क्यों JRuby नई कक्षाएं बना रहा है, लेकिन मुझे समझ में नहीं आ रहा है कि वे क्यों साफ नहीं हो जाते हैं ... – organicveggie

+0

मैं कैसे बता सकता हूं कि jruby.compile.mode = OFF सही तरीके से काम कर रहा है या नहीं? मैंने जोड़ा- djruby.compile.mode = catalina.sh में CATALINA_OPTS को बंद करें, टॉमकैट शुरू किया और साइट के खिलाफ एक वेबक्रॉलर लॉन्च किया। जेकोनसोल इंगित करता है कि कुल वर्ग गणना और कुल परमिट लगातार बढ़ रहा है। – organicveggie

1

प्रोफ़ाइलिंग टूल, और लोग हैं, जो जानते हैं कि कैसे उन्हें इस्तेमाल करने हैं। मैं उनमें से एक नहीं हूं, मुझे डर है।

ब्रूट बल सलाह:

पुनरारंभ अपने बिलाव हर 8 घंटे। आपके उपयोगकर्ताओं द्वारा देखी गई कुल डाउनटाइम बहुत स्वीकार्य होगी।समस्या हल हो;)


संपादित

ओह, सब ठीक! The boring solution

+0

धन्यवाद, लेकिन हर 8 घंटों में टॉमकैट को पुनरारंभ करना स्वीकार्य समाधान नहीं है। खासकर जब से मैं वह लड़का हूं जो ऐसा कर रहा है। :) यहां बिंदु अंतर्निहित समस्या को हल करना है। – organicveggie

+0

'cron' और दोस्तों का आविष्कार किया गया था इसलिए आपको मैन्युअल रूप से पुनरारंभ करने की आवश्यकता नहीं होगी। आपको एक समस्या है जो या तो आपके रूबी कोड या JRuby के कार्यान्वयन या उस और टॉमकैट के अस्पष्ट संयोजन में है, इसलिए यह सिर्फ "मानक" जावा मेमोरी समस्या भी नहीं है। मुझे लगता है कि आप इसे ठीक करने से पहले अपने सर्वर को कई बार पुनरारंभ करेंगे, इसलिए नियमित रूप से रीस्टार्ट स्क्रिप्टिंग को देखना बुद्धिमान होगा। –

+0

बिल्कुल। लेकिन मैं टॉमकैट को रोकने और शुरू करने की प्रक्रिया के साथ बहुत सहज हूं और इसे स्वचालित कर रहा हूं। हमें यह नियंत्रण में मिला है। लेकिन प्रत्येक 8 घंटे डाउनटाइम, भले ही यह केवल 30-60 सेकेंड है, प्रबंधन को स्वीकार्य नहीं माना जाता है। आपको पता है कि यह कैसे होता है। :) तो मेरा प्रश्न वास्तव में समस्या के स्रोत को ट्रैक करने के तरीके पर सलाह की तलाश में है। – organicveggie

2

हमें जेराबी 1.5.1: का उपयोग कर सिनात्रा वेब एप्लिकेशन के साथ समान समस्या थी। JVM TraceClassLoading विकल्प प्रत्येक अनुरोध के साथ लोड किया गया anon_class * प्रिंट करता है।

उस अज्ञात वर्ग को लोड करने के लिए कभी-कभी खर्च करने के बाद, जो कंसोल पर ट्रेस स्टेटमेंट प्रिंट करके किया जाता है, हमने अंततः यह पता लगाया कि यह जावा ऑब्जेक्ट पर एक लापता विधि को कॉल करने के कारण हुआ था।

उस कॉल ने जावा ऑब्जेक्ट में उस लापता विधि को जोड़ने के लिए जेआरबी को ट्रिगर किया। उस प्रक्रिया ने एक नया सिंगलटन जेआरबी क्लास बनाया, जिसे "anon_class" नाम दिया गया था जिसके बाद कुछ हैश मान थे। चूंकि यह एक वर्ग प्रकार है, यह पर्मजेन में रहता है और कभी भी जीसी द्वारा एकत्र नहीं किया जाता है।

कामकाज उस लापता विधि को कॉल करने या कार्यान्वयन प्रदान करने से बचने के लिए है। हमारे मामले में, हम Java ArrayList ऑब्जेक्ट पर ब्लॉक के साथ सॉर्ट विधि को कॉल करने का प्रयास कर रहे थे। यदि हम Java ArrayList को JRuby सरणी में कनवर्ट करने के लिए पहले "to_a" विधि को कॉल करते हैं, तो ब्लॉक के साथ क्रमबद्ध करें anon_class नहीं बनाएगा।

तो, मैं जेआरडी से जावा ऑब्जेक्ट तक पहुंचने वाले स्थानों के लिए कोड की समीक्षा करने का सुझाव दूंगा।

require 'java' 
include_class java.util.ArrayList 

list = ArrayList.new 
list << 3 
list << 2 
list << 1 

3.times do 
    new_list = list.sort { |a, b| a <=> b} 
    #new_list = list.to_a.sort { |a, b| a <=> b} 
    puts new_list 
end 

मान लें फ़ाइल नाम test_classload.rb है, का पालन कर रहे आउटपुट: $ JRuby -J-XX: test_classload TraceClassLoading +

2

बस इस समस्या को और वैकल्पिक हल को दिखाने के लिए एक सरल उदाहरण प्रदान करते हैं।आरबी | कोई anon_class: ग्रेप anon_class


[लोडेड anon_class729155693_307995574 JVM_DefineClass से] [लोडेड anon_class1690464956_307995577 से JVM_DefineClass]

तो टिप्पणी की लाइन के लिए स्विच, उत्पादन में खाली है [लोडेड JVM_DefineClass से anon_class819349464_307995535] लदा हुआ।