जावा में कक्षाएं उतारना?


174

मेरे पास एक कस्टम क्लास लोडर है, ताकि एक डेस्कटॉप एप्लिकेशन डायनेमिक रूप से एक AppServer से कक्षाएं लोड करना शुरू कर सके, जिनसे मुझे बात करने की आवश्यकता है। हमने ऐसा तब किया जब जार की मात्रा जो ऐसा करने के लिए आवश्यक है, हास्यास्पद हैं (यदि हम उन्हें जहाज करना चाहते थे)। यदि हम डायनेमिक रूप से क्लासेस को लोड समय पर लोड नहीं करते हैं तो हमारे पास वर्जन समस्याएँ हैं।

अब, मुझे सिर्फ एक समस्या है जहां मुझे दो अलग-अलग AppServers से बात करने की आवश्यकता है और पाया कि जिनकी कक्षाएं मैं पहले लोड करता हूं, उनके आधार पर मैं बुरी तरह से टूट सकता हूं ... क्या वास्तव में JVM को मारे बिना कक्षा को उतारने के लिए मजबूर करने का कोई तरीका है?

आशा है कि यह समझ में आता है


क्या आपके पास प्रत्येक जार के लिए एक क्लास लोडर है? क्लास लोडर को उतारने के लिए OSGI कंटेनर कैसे संग्रहीत करता है? ऐसा लगता है कि क्लास लोडर क्लास में कोई अनलोड एपीआई नहीं है?
hetaoblog

जवाबों:


190

एक ही तरीका है कि एक क्लास अनलोड किया जा सकता है अगर क्लासलोडर का उपयोग कचरा एकत्र किया जाता है। इसका मतलब है, हर एक वर्ग के संदर्भ में और क्लास लोडर को खुद डोडो के रास्ते पर जाने की जरूरत है।

आपकी समस्या का एक संभावित समाधान प्रत्येक जार फ़ाइल के लिए एक क्लास लोडर, और प्रत्येक AppServers के लिए एक क्लास लोडर है जो विशिष्ट जार क्लास लोडर के लिए कक्षाओं के वास्तविक लोडिंग को दर्शाता है। इस तरह, आप हर ऐप सर्वर के लिए जार फ़ाइल के विभिन्न संस्करणों को इंगित कर सकते हैं।

यह तुच्छ नहीं है, हालांकि। OSGi प्लेटफ़ॉर्म बस ऐसा करने का प्रयास करता है, क्योंकि प्रत्येक बंडल में एक अलग क्लास लोडर होता है और निर्भरताएं प्लेटफ़ॉर्म द्वारा हल की जाती हैं। हो सकता है कि एक अच्छा समाधान इस पर एक नज़र रखना होगा।

यदि आप OSGI का उपयोग नहीं करना चाहते हैं, तो हर JAR फ़ाइल के लिए जारक्लास लोडर वर्ग के एक उदाहरण का उपयोग करना संभव हो सकता है ।

और एक नया, MultiClassloader Class बनाएं जो Classloader का विस्तार करता है। इस वर्ग में आंतरिक रूप से जारक्लास लोडरों की एक सरणी (या सूची) होगी, और डिफाइंडक्लिप में () विधि सभी आंतरिक क्लास लोडर के माध्यम से पुनरावृत्ति करेगी जब तक कि कोई परिभाषा नहीं मिल सकती है, या NoClassDefFoundException को फेंक दिया गया है। क्लास में नए जारक्लास लोडर्स को जोड़ने के लिए एक दो एक्सेसर मेथड उपलब्ध कराए जा सकते हैं। एक MultiClassLoader के लिए नेट पर कई संभावित कार्यान्वयन हैं, इसलिए आपको अपना स्वयं का लिखने की आवश्यकता भी नहीं हो सकती है।

यदि आप सर्वर से हर कनेक्शन के लिए एक मल्टीक्लासर लोड करते हैं, तो सिद्धांत रूप में यह संभव है कि प्रत्येक सर्वर एक ही वर्ग के भिन्न संस्करण का उपयोग करता है।

मैंने एक प्रोजेक्ट में MultiClassloader विचार का उपयोग किया है, जिसमें उपयोगकर्ता-परिभाषित स्क्रिप्ट वाले वर्गों को लोड किया जाना था और मेमोरी से अनलोड किया गया था और यह काफी अच्छी तरह से काम करता था।


31
यह भी ध्यान दें कि java.sun.com/docs/books/jls/second_edition/html/… के अनुसार कक्षाओं को उतारना एक अनुकूलन है और, JVM कार्यान्वयन के आधार पर, वास्तव में हो सकता है या नहीं भी हो सकता है।

5
OSGi के लिए एक आसान और हल्के विकल्प के रूप में, JBoss मॉड्यूल की कोशिश करें - प्रति क्लासलोडर प्रति मॉड्यूल (जार का एक समूह) के साथ मॉड्यूलर क्लासिंग।
ओन्ड्रा उइस्का

42

हां, कक्षाओं को लोड करने और बाद में उन्हें "अनलोड" करने के तरीके हैं। ट्रिक अपने स्वयं के क्लास लोडर को लागू करने के लिए है जो उच्च स्तर के क्लास लोडर (सिस्टम क्लास लोडर) और ऐप सर्वर (एस) के क्लास लोडर के बीच रहता है, और यह आशा करता है कि ऐप सर्वर के क्लास लोडर ऊपरी लोडर को क्लास लोडिंग सौंपते हैं। ।

एक वर्ग को उसके पैकेज, उसके नाम और मूल रूप से लोड किए गए वर्ग लोडर द्वारा परिभाषित किया जाता है। एक "प्रॉक्सी" क्लास लोडर को प्रोग्राम करें जो जेवीएम शुरू करते समय पहले लोड किया जाता है। कार्यप्रवाह:

  • कार्यक्रम शुरू होता है और वास्तविक "मुख्य" -क्लास इस प्रॉक्सी क्लास लोडर द्वारा लोड किया जाता है।
  • प्रत्येक वर्ग जो तब सामान्य रूप से लोड किया जाता है (यानी किसी अन्य क्लास लोडर कार्यान्वयन के माध्यम से नहीं जो पदानुक्रम को तोड़ सकता है) को इस वर्ग लोडर को सौंप दिया जाएगा।
  • प्रॉक्सी क्लास लोडर डेलिगेट करता है java.xऔर sun.xसिस्टम क्लास लोडर (इन्हें सिस्टम क्लास लोडर की तुलना में किसी अन्य क्लास लोडर के माध्यम से लोड नहीं किया जाना चाहिए )।
  • प्रत्येक वर्ग के लिए जो बदली है, एक क्लास लोडर को तुरंत रोकें (जो वास्तव में कक्षा को लोड करता है और इसे अभिभावक वर्ग लोडर को नहीं सौंपता है) और इसके माध्यम से लोड करता है।
  • डेटा संरचना में मानों और क्लास लोडर के पैकेज / नाम को स्टोर करें (हैशमैप)।
  • हर बार जब प्रॉक्सी क्लास लोडर को उस क्लास के लिए रिक्वेस्ट मिलती है, जिसे पहले लोड किया गया था, तो वह क्लास लोडर से क्लास को पहले स्टोर कर देता है।
  • यह आपके वर्ग लोडर (या अपने डेटा संरचना से कुंजी / मूल्य जोड़ी को "हटाने") के लिए एक वर्ग के बाइट सरणी का पता लगाने के लिए पर्याप्त होना चाहिए और यदि आप इसे बदलना चाहते हैं तो कक्षा को फिर से लोड करें।

डन वहीं एक नहीं आना चाहिए ClassCastException या LinkageError आदि

वर्ग लोडर पदानुक्रमों के बारे में अधिक जानकारी के लिए (हाँ, यह वही है जो आप यहाँ लागू कर रहे हैं; -) टेड न्यूअर्ड द्वारा "सर्वर-आधारित जावा प्रोग्रामिंग" को देखें - उस पुस्तक ने मुझे जो आप चाहते हैं उसके समान कुछ लागू करने में मदद की।


3
मैं ऐसे लोगों को नहीं समझता, जिन्होंने बिना टिप्पणी छोड़े इस उत्तर के लिए -1 पर टिक किया। मेरे लिए अच्छा लग रहा है। शायद ClassLoaderप्रति वर्ग एक होना बहुत अधिक है, एक ClassLoaderप्रति JAR समझ में आता है। प्रस्तावित स्कीमा में वर्ग अपलोड को बाध्य करने के बारे में अधिक विशिष्ट हो सकता है? उदाहरण के लिए, मैं कैसे गारंटी दे सकता हूं कि ClassLoaderB द्वारा भरी गई कक्षाओं के उदाहरणों को ClassLoaderB द्वारा लोड किए गए उदाहरणों द्वारा संदर्भित नहीं किया जाता है?
dma_k

@dma_k वास्तव में, उत्तर अच्छा है, लेकिन यह आपके द्वारा उल्लेखित प्रमुख बिंदुओं को नहीं छू रहा है।
zinking

@Georgi एक मौजूदा कार्यान्वयन है जिसे हम इसके लिए प्रेरित / पुन: उपयोग कर सकते हैं?
स्लेज

1
यह बहुत मददगार होगा, यदि आप नमूना जावा कोड प्रदान कर सकते हैं। सटीक होने के लिए, मैं देख रहा हूं कि कस्टमक्लासैलाडर का उपयोग करके कक्षाओं को कैसे उतारना है, लेकिन कोई भाग्य नहीं था।
श्रीहर्ष

@ Sriharshag.rv क्या आपने यह कोशिश की है और एक नमूना लागू किया है?
निओमिंगजियन

17

मैंने एक कस्टम क्लास लोडर लिखा, जिसमें से क्लास लोडर को जीसी के बिना अलग-अलग कक्षाओं को अनलोड करना संभव है। जार क्लास लोडर


एक जादू की तरह काम करता है :)। क्या जार फ़ाइल के सभी वर्ग फ़ाइलों को अनलोड करने की कोई विधि है?
एरकेन

दुर्भाग्य से फिलहाल नहीं। लेकिन इस पर गौर करेंगे। भविष्य के रिलीज में हो सकता है।
कामरान

वैसे, मुझे थोड़ा वर्कअराउंड मिला। यदि आपके पास JarClassLoaderभरी हुई प्रत्येक जार फ़ाइल के लिए एक है , तो आप इस getLoadedClasses()पर कॉल कर सकते हैं , फिर प्रत्येक पर पुनरावृति कर सकते हैं और इसे अनलोड कर सकते हैं।
एर्केन

12

क्लास लोडर एक मुश्किल समस्या हो सकती है। आप विशेष रूप से समस्याओं में भाग सकते हैं यदि आप कई क्लास लोडर का उपयोग कर रहे हैं और उनकी बातचीत स्पष्ट रूप से और सख्ती से परिभाषित नहीं है। मुझे लगता है कि वास्तव में एक वर्ग youlre जाने के लिए किसी भी वर्ग (और उनके उदाहरणों) को हटाने के लिए आप को उतारने की कोशिश कर रहे हैं सभी संदर्भों को हटाने में सक्षम हैं।

ज्यादातर लोगों को इस तरह की चीज की जरूरत होती है जो OSGi का उपयोग करते हुए खत्म हो जाए । OSGi वास्तव में शक्तिशाली और आश्चर्यजनक रूप से हल्का और उपयोग में आसान है,


7

आप एक ClassLoader को अनलोड कर सकते हैं लेकिन आप विशिष्ट कक्षाओं को अनलोड नहीं कर सकते। अधिक विशेष रूप से आप एक क्लासलोडर में बनाई गई कक्षाओं को अनलोड नहीं कर सकते हैं जो आपके नियंत्रण में नहीं हैं।

यदि संभव हो तो, मैं सुझाव देता हूं कि आप अपने स्वयं के क्लासऑलडर का उपयोग करें ताकि आप अनलोड कर सकें।


4

कक्षाओं में उनके ClassLoader उदाहरण, और इसके विपरीत में एक मजबूत संदर्भ है। वे जावा ऑब्जेक्ट्स के समान कचरा एकत्र करते हैं। टूल इंटरफ़ेस या समान हिटिंग के बिना, आप अलग-अलग कक्षाएं नहीं निकाल सकते।

हमेशा की तरह आप मेमोरी लीक्स प्राप्त कर सकते हैं। आपकी किसी कक्षा या कक्षा लोडर का कोई भी मजबूत संदर्भ पूरी बात को लीक कर देगा। यह उदाहरण के लिए, ThreadLocal, java.sql.DriverManager और java.beans के सूर्य कार्यान्वयन के साथ होता है।


-1

यदि आप देख रहे हैं कि यदि अनलोडिंग क्लास जेकोनोसोल या कुछ और में काम करती है, तो java.lang.System.gc()अपने क्लास अनलोडिंग लॉजिक के अंत में जोड़ने का प्रयास करें। यह कचरा कलेक्टर को स्पष्ट रूप से ट्रिगर करता है।


3
सावधान: System.gc () आवश्यक कॉल GC नहीं है। यह केवल jvm को इसे शुरू करने के लिए कहता है, लेकिन यह इसे लागू नहीं करता है। और IME यह अक्सर GC को शुरू नहीं करता है: - \
Juh_
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.