2010-11-19 18 views
5

मैं एक तृतीय पक्ष लाइब्रेरी का उपयोग कर रहा हूं जो गतिशील रूप से जावा कक्षाओं के उदाहरण बनाता है और Introspector.getBeanInfo की सहायता से उन उदाहरणों को पॉप्युलेट करता है। कुछ अनुरोधों के परिणामस्वरूप 5 या 6 लगातार कॉल Introspector.getBeanInfo पर हो सकती हैं। मैंने पाया है कि जब एप्लिकेशन लगभग एक घंटे तक निष्क्रिय होता है या तो Introspector.getBeanInfo पर पहली कॉल को बाद में कॉल (< 100 मिलीसेकंड) बनाम (20-60 सेकेंड) निष्पादित करने में काफी लंबा समय लगता है। अगले कुछ मिनटों में किए गए कॉल < 100 मिलीसेकंड लेते रहेंगे, लेकिन जब मैं एक और घंटे इंतजार करता हूं तो पहले कॉल में 20-60 सेकंड लगते हैं।निष्क्रियता के बाद java.beans.Introspector.getBeanInfo को कॉल करते समय प्रदर्शन समस्याएं

एक साधारण परीक्षण अनुप्रयोग के साथ व्यवहार को फिर से बनाने के प्रयास में मुझे एक समान व्यवहार मिला है जब एक जावा एप्लिकेशन स्वयं एक घंटे तक नहीं चलाया जाता है। उदाहरण के लिए, यदि मैं निम्नलिखित कंसोल ऐप चलाता हूं तो इसे पूरा करने में 15 मिलीसेकंड लग सकते हैं। यदि मैं एक घंटे प्रतीक्षा करता हूं और एप्लिकेशन को फिर से चलाता हूं तो इसे पूरा होने में 20 सेकंड लगते हैं।

long start = System.currentTimeMillis(); 
System.out.println("Start"); 
Introspector.getBeanInfo(MyClass.class, Object.class); 
long end = System.currentTimeMillis(); 
System.out.println("End: " + (end-start)); 

मैं मूल रूप से सोचा था कि तथ्य यह है कि इस मुद्दे को Introspector वर्ग प्रयास मानक नामकरण सम्मेलनों के आधार पर कक्षाओं के उदाहरण है कि अपने आवेदन में मौजूद नहीं है (उदाहरण के लिए, MyClassBeanInfo) बनाने के लिए से संबंधित हो सकता है, और यह था उन वर्गों को खोजने के प्रयास में जार फ़ाइलों को स्कैन करने में काफी समय लग रहा है (मेरे जावा एप्लिकेशन में 100 से अधिक संदर्भित जार फाइलें हैं), लेकिन मैंने प्रतिबिंब का उपयोग करके Introspector.getBeanInfo(MyClass.class, Object.class, Introspector.IGNORE_ALL_BEANINFO) कहा (यह सूर्य के जेआरई में एक निजी विधि है जो देखकर कोड बीनइन्फो कक्षाओं के लुकअप को छोड़ने लगता है), और मैं अभी भी देरी को पुन: उत्पन्न करने में सक्षम था।

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

एक साइड नोट के रूप में मैं विंडोज एक्सपी पर जेडीके 1.6.0_21 का उपयोग कर रहा हूं। मैं उपयोग कर रहा हूँ तीसरी पार्टी लाइब्रेरी BlazeDS है। मेरा आवेदन स्प्रिंग/ब्लेज़डीएस एकीकरण का उपयोग कर टोमकैट में होस्ट किया गया है। flex.messaging.io.BeanProxy की विधि में Introspector.getBeanInfo पर कॉल करने के लिए (जहां Introspector.getBeanInfo पर कॉल किया गया है) को इंगित करने के लिए मैं कई ब्लजडेड कक्षाओं को ओवरराइट करता हूं। इसके अलावा, BlazeDS BeanInfo को कैश करता है, इसलिए Introspector.getBeanInfo पर कॉल केवल तब किया जाता है जब ब्लेज़ किसी ऑब्जेक्ट को deserializing कर रहा है जिसे जावा क्लास में मैप किया गया है जिसे अभी तक संसाधित नहीं किया गया है। इसलिए, मेरे पास इस मुद्दे के आसपास काम करने के अन्य तरीके हैं, लेकिन मैं वास्तव में जानना चाहूंगा कि इस व्यवहार के लिए वैध स्पष्टीकरण है या नहीं।

संपादित करें: मैंने समस्या को पुन: उत्पन्न करते समय कई बार प्रक्रिया पर jstack चलाया (धन्यवाद @ टॉम) और पुष्टि की कि यह जार फ़ाइलों को लोड करने से संबंधित है। मैं एक 20 सेकंड समय सीमा (देरी के कुल समय) पर धागे 5 बार फेंक दिया और हर बार निम्न परिणाम का उत्पादन किया:

"http-8080-exec-6" daemon prio=6 tid=0x65cae800 nid=0x1a50 runnable [0x67a3d000] 
    java.lang.Thread.State: RUNNABLE 
    at java.util.zip.ZipFile.open(Native Method) 
    at java.util.zip.ZipFile.<init>(Unknown Source) 
    at java.util.jar.JarFile.<init>(Unknown Source) 
    at java.util.jar.JarFile.<init>(Unknown Source) 
    at org.apache.catalina.loader.WebappClassLoader.openJARs(WebappClassLoader.java:2704) 
    at org.apache.catalina.loader.WebappClassLoader.findResourceInternal(WebappClassLoader.java:2945) 
    - locked <0x1804cc18> (a [Ljava.util.jar.JarFile;) 
    at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2739) 
    at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1144) 
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1639) 
    - locked <0x1803dd38> (a org.apache.catalina.loader.WebappClassLoader) 
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1517) 
    at java.beans.Introspector.instantiate(Unknown Source) 
    at java.beans.Introspector.findExplicitBeanInfo(Unknown Source) 
    - locked <0x434649a0> (a java.lang.Class for java.beans.Introspector) 
    at java.beans.Introspector.<init>(Unknown Source) 
    at java.beans.Introspector.getBeanInfo(Unknown Source) 
    - locked <0x181bed70> (a java.lang.Object) 

मैं मदद नहीं कर सकता लेकिन लगता है कि JRE/JVM जार के कुछ प्रकार है कैश जो एक घंटे के बाद समाप्त हो रहा है और जार फ़ाइलों को फिर से स्कैन करने के लिए मजबूर कर रहा है, लेकिन मुझे ऐसे व्यवहार को रेखांकित करने वाले ऑनलाइन कुछ भी नहीं मिल रहे हैं।

संपादित करें: जैसा कि यह पता चला है कि टॉमकैट WebappClassLoader कैश जेएआर फाइल करता है और समय-समय पर कैश को शुद्ध करता है। अब यह पता लगाने के लिए कि क्या कैश किसी भी तरह कॉन्फ़िगर करने योग्य है ...

संपादित करें: टोमकैट पिछली बार एक जार फ़ाइल तक पहुंचने के 90 सेकंड बाद सभी जेएआर फाइलों को बंद कर देता है। जार फ़ाइलों को बंद होने पर प्रिंट करने के लिए मैं WebappClassLoader को ओवरराइट करता हूं। जार फ़ाइलों को बंद करने के बाद मैंने देरी को पुन: उत्पन्न करने की कोशिश की, लेकिन इसमें असमर्थ था।तो, यह मुझे बताता है कि या तो एक जेआरई/जेवीएम जार फ़ाइल कैश है, या ऑपरेटिंग सिस्टम (या मेरी मशीन, एंटीवायरस, आदि) में कुछ अंतर्निहित है जो लंबे विलंब के बाद धीमी लोड के समय का कारण बन रहा है। अभी भी इस पर काम कर रहे हैं ...

+1

आप 'jstack' का उपयोग करने की कोशिश कर सकते हैं या यह देखने के लिए कि प्रोग्राम कहां मिल गया है। इसके अलावा, कोई नेटवर्क कनेक्शन शामिल है? –

+0

yourkit प्रोफाइलर आपका दिन बचा सकता है .. सूरज जावा कोड में दिखना ठीक है और आप दिलचस्प चीजें सीख सकते हैं लेकिन यह बहुत अधिक समय लेता है। –

+0

धन्यवाद @ टॉम - jstack –

उत्तर

3

मेरे नियोक्ता पर, हम भी गतिशील रूप से जेनरेट किए गए वर्गों पर भारी निर्भर हैं। Introspector की समस्याओं और यह कैसे व्यवहार करता है (उदाहरण के लिए क्लासलोडर व्यवहार पर निर्भर करता है) और कई *BeanInfo कक्षाओं को लोड करने का प्रयास कर रहा है, जो हमारे पास नहीं है, यह हमारे लिए कोई नहीं था और हमने इंट्रोस्पेक्टर का उपयोग नहीं करने और कार्यक्षमता को फिर से लागू करने का निर्णय लिया हमारा अपना।

यह सुनिश्चित नहीं है कि आपको वास्तव में कितनी बीनइन्फो की ज़रूरत है, लेकिन प्रतिबिंब और घर से उगाए गए संपत्ति-मेटाडाटा-सूचना घटक का उपयोग करना आसान हो सकता है, जो आपके नियंत्रण में बेहतर है। और आसान के साथ, मेरा मतलब यह भी है कि जब आप अन्य एप्लिकेशन सर्वर पर ऐप को तैनात करते हैं तो आपके द्वारा सुरक्षित तंत्रिकाएं सुरक्षित होती हैं, जिनमें उनके स्वयं के क्लासलोडर व्यवहार होते हैं और जो कि टॉमकैट पर भी अधिक भारी और असुरक्षित होते हैं।

बीनइन्फो और संबंधित घटक इंटरफेस हैं, इसलिए आपको केवल इंट्रोस्पेक्टर को फिर से लागू करने की आवश्यकता हो सकती है, न कि आपके सभी कोड जो इसका उपयोग करते हैं।

+0

चलाने के बाद उपरोक्त संपादन देखें सुझावों के लिए धन्यवाद। दुर्भाग्यवश, पहला सुझाव हमारे लिए एक विकल्प नहीं है क्योंकि हम तृतीय पक्ष पुस्तकालयों का उपयोग कर रहे हैं जो Introspector.getBeanInfo पर भरोसा करते हैं। इंट्रोस्पेक्टर वर्ग को ओवरराइड करने का रास्ता हो सकता है। अभी मैं टॉमकैट क्लासलोडर को ओवरराइड करने की ओर झुका रहा हूं (जो निश्चित रूप से केवल टॉमकैट में काम करेगा, लेकिन हमारी वर्तमान जरूरतों के लिए पर्याप्त है)। –

0

जैसा कि मैंने उल्लेख किया है, WebAppClassLoader टॉमकैट में डिफ़ॉल्ट कैश जेएआर फाइल 90 सेकंड के लिए। 90 सेकंड के बाद Introspector.getBeanInfo पर कॉल करते समय मैंने सत्यापित किया कि टोमकैट JAR फ़ाइलों को पुनः लोड कर रहा था। कुछ मिनट की निष्क्रियता के बाद देरी कम थी, लेकिन अभी भी देरी हुई थी। मैंने कभी यह निर्धारित नहीं किया कि देरी की एक घंटे के बाद देरी इतनी लंबी क्यों थी।

आखिरकार, मेरा समाधान WebAppClassLoader को ओवरराइड करना था और अनिवार्य रूप से जार को कैश करना था। हमारे परिदृश्य में यह पूरी तरह स्वीकार्य है क्योंकि हम अपने आवेदन में टॉमकैट लपेट रहे हैं, ऐसे कोई अन्य वेब एप्लिकेशन नहीं हैं जो टोमकैट के समान उदाहरण साझा करते हैं, और हम अपने वेब एप्लिकेशन को स्वचालित रूप से पुनः लोड करने की अनुमति नहीं देते हैं। यदि आप एक समान समाधान को लागू करने पर विचार कर रहे हैं तो इसे ध्यान में रखें।

यहाँ JAR कैशिंग व्यवहार ओवरराइड करने के लिए कोड है (cacheJarFiles कि मैं WebAppClassLoader वर्ग में शामिल किया है एक कस्टम बूलियन है):

private static boolean cacheJarFiles = true; 

...

public void closeJARs(boolean force) { 
    if (cacheJarFiles) { 
     return; 
    } 
    if (jarFiles.length > 0) { 
     synchronized (jarFiles) { 
     if (force || (System.currentTimeMillis() 

...

} 

अनिवार्य रूप से, मैंपर कॉल निरस्त कर रहा हूं। प्रदर्शन में वृद्धि जो हम अब देख रहे हैं वह काफी हद तक पर्याप्त है। निष्क्रियता के एक घंटे बाद हम Introspector.getBeanInfo पर नई कॉल पर 10-60 + सेकेंड बचाते हैं। निष्क्रियता के कुछ मिनटों के बाद हम 100-200 मिलीसेकंड बचाते हैं।

1

java.beans.Introspector ओएसजीआई पर्यावरण में एक वास्तविक समस्या हो सकती है जहां की खोज गैर-मौजूदा कक्षाएं कणिक महंगी हो सकती हैं। दोस्त वर्ग लोडिंग के कारण यह विषुव में विशेष रूप से सच है: Eclipse-BuddyPolicy: depenent और Eclipse-BuddyPolicy: global गंभीर प्रदर्शन समस्याओं का कारण बन सकता है।

java.beans.Introspector कुछ अप्रत्याशित स्थानों

  • org.apache.log4j.config.PropertySetter
  • org.springframework.beans.CachedIntrospectionResults
  • org.hibernate.util.Cloneable#copyListeners

आम तौर पर जब Introspector.IGNORE_ALL_BEANINFO फ्लैग निर्दिष्ट किया है Introspector विषुव में अपेक्षाकृत सुरक्षित होना चाहिए में प्रयोग किया जाता है। ऐसा नहीं है, वर्तमान ओरेकल JVM कार्यान्वयन में बीकॉज़ बीनइन्फो कैशिंग का उपयोग तब तक नहीं किया जाता जब तक Introspector.USE_ALL_BEANINFO निर्दिष्ट नहीं किया जाता है। जाहिर है, जावाडॉक्स के साथ सीधे संघर्ष में, इसलिए मैं कहूंगा कि यह वास्तव में इंट्रोस्पेक्टर कार्यान्वयन (या दस्तावेज़ीकरण) में एक बग है।

+1

मैंने देखा कि यदि 'Introspector.IGNORE_ALL_BEANINFO' को पैरामीटर के रूप में दिया गया है, तो कक्षाएं * * बीनइन्फो 'अब और नहीं देखी गई हैं। हालांकि, ऐसा लगता है कि एल्गोरिदम को '* कस्टमाइज़र' के लिए देखने के लिए कोई रास्ता नहीं है। – Cristian

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