2009-01-05 6 views
18

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

एक उपयोगिता विधि संजीदगी से आह्वान करने के लिए पर विचार करें:

public static Object invoke(Object targetObject, String methodName, Object[] arguments, Class<?>[] signature) 

बुनियादी आपरेशन

return method.invoke(targetObject, arguments); 

एक प्रदर्शन के अनुकूलन के रूप में है, मैं विधि लक्ष्य वस्तु की क्लास, मेथड नाम का एक हैश का उपयोग कर कैश और हस्ताक्षर (जिसमें से कोड कुछ सुधार का उपयोग कर सकता है) लेकिन उससे परे, क्या मैं और कुछ कर सकता हूं? मैंने InvokeDynamic के कुछ शुरुआती कार्यान्वयन के संदर्भों को सुना है जो ध्वनि का वादा करता है, लेकिन मुझे लगता है कि वे शायद अभी तक लागू नहीं हैं, और मैंने अपने बाइट कोड मैनिपुलेशन को छूट दी क्योंकि मैं उपयोगिता को सरल (लेकिन तेज़) रखना चाहता हूं।

चीयर्स।

उत्तर

49

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

java.lang.Class कुछ कैशिंग स्वयं करता है, इसलिए अपने स्वयं के कैश को लागू करने से चीजों में काफी सुधार नहीं हो सकता है। मैन्युअल कैशिंग के साथ और बिना समय परीक्षण करें।

वास्तविक आमंत्रण तंत्र भी अनुकूलित किया गया है। आपकी प्रतिबिंबित विधि के पहले 15 रन (डिफ़ॉल्ट रूप से) को जेएनआई का उपयोग करके बुलाया जाता है; उसके बाद, बाइटकोड उत्पन्न होता है और उस परावर्तित विधि को कॉल करना उस विधि को सीधे जावा कोड में कॉल करने के लिए समान रूप से प्रदर्शन करेगा।

+1

वाह मैं उसे कभी नहीं जानता था। मैं उन समय परीक्षण करूँगा। क्या 15 डिफ़ॉल्ट को ओवरराइड करने का कोई तरीका है? कंपाइलर को जल्दी में लात मारने के लिए राजी करने का कोई और तरीका? – Nicholas

+8

बस अपनी पसंद की संख्या में sun.reflect.inflationTreshold संपत्ति सेट करें। –

0

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

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

+0

स्वीकार किया गया, लेकिन थोड़ी चुस्त होने की प्रक्रिया में, मैंने पाया कि गैर-सार्वजनिक तरीकों को माता-पिता में विधियों को खोजने के लिए विरासत के पेड़ पर चढ़ने की आवश्यकता है, इसलिए मुझे कई मामलों को कॉल करने की आवश्यकता है [घोषित] विधि कई बार। इसके अलावा, मुझे केवल एक बार सेट असफल (सत्य) कॉल करना होगा। क्या मैं अभी भी आधार से बाहर हूं? – Nicholas

+0

मुझे नहीं लगता कि आप आधार से बाहर हैं, यह एक दिलचस्प विश्लेषण है, लेकिन जब तक आपको आवश्यकता न मिल जाए, आपको हमेशा सबसे अधिक पढ़ने योग्य, सरल और प्रत्यक्ष समाधान का उपयोग करना चाहिए जिसके साथ आप आ सकते हैं। –

1

आप निश्चित रूप से केवल एक बार (संभवतः एक निजी स्थैतिक के रूप में) विधि वस्तु को प्रतिबिंबित करना चाहते हैं, और इसे हर बार इसे प्रतिबिंबित करने के बजाय आमंत्रण के लिए उपयोग करना चाहते हैं। कैश मैप से परेशान न हों जबतक कि आप संकलन समय पर नाम नहीं जानते।

यदि यह आपके संदर्भ में समझदार है, तो आप तर्क सरणी ऑब्जेक्ट पर लटकना और पुन: उपयोग करना चाहते हैं (अस्थायी जीसी अवरोध को रोकने के लिए विधि निकास पर सरणी तत्वों को शून्य करना न भूलें)।

यदि हमेशा एक ही पैरा (अत्यधिक संभावना नहीं) के साथ बुलाया जाता है, तो आप परम पर लटका सकते हैं और (इसके मूल्यों के साथ तर्क सरणी) उनका पुन: उपयोग कर सकते हैं।

मैं अन्य उत्तरों द्वारा पहले से दिए गए कारणों से परे कुछ भी प्रयास नहीं करता।

5

मैंने क्रिस जेस्टर-यंग के उत्तर के आसपास कुछ परीक्षण चलाए और वर्बोज विकल्पों का उपयोग करके, मैंने निश्चित रूप से संकलक 15 वें आमंत्रण के आसपास कुछ कार्रवाई की। यह कहना मुश्किल है कि अधिक परिष्कृत परीक्षण के बिना बहुत अधिक प्रदर्शन अंतर है, लेकिन यह प्रेरक है। यहाँ उत्पादन है:

Test# 0 
Test# 1 
Test# 2 
Test# 3 
Test# 4 
Test# 5 
Test# 6 
Test# 7 
Test# 8 
Test# 9 
Test# 10 
Test# 11 
Test# 12 
Test# 13 
Test# 14 
[Loaded sun.reflect.ClassFileConstants from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.AccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.MethodAccessorGenerator from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ByteVectorFactory from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ByteVector from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ByteVectorImpl from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ClassFileAssembler from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.UTF8 from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded java.lang.Void from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.Label from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.Label$PatchInfo from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded java.util.AbstractList$Itr from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.MethodAccessorGenerator$1 from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ClassDefiner from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.ClassDefiner$1 from C:\jdk1.5.0_06\jre\lib\rt.jar] 
[Loaded sun.reflect.GeneratedMethodAccessor1 from __JVM_DefineClass__] 
Test# 15 
Test# 16 
Test# 17 

मुझे लगता है कि InvokeDynamic व्यापार प्रतिबिंब speedup/उन्मूलन के आधार पर भी कई डेवलपर्स को आकर्षित नहीं कर रहा है।

धन्यवाद क्रिस।

0

यदि विधि में चलने की लागत के 10% से कम की कमी की लागत है, तो इसके बारे में चिंता करने योग्य नहीं है।

आप यह निर्धारित कर सकते हैं कि इसे लूप में 10^6 बार चलाकर, दिनचर्या के साथ और बिना। इसे स्टॉपवॉच के साथ समय दें, इसलिए सेकेंड माइक्रोसेकंड में अनुवाद करते हैं।

+0

प्रतिशत लागत वास्तव में उस विधि पर निर्भर करेगी जो वास्तव में कर रही है। – Nicole

+0

@ उत्पत्ति: ठीक है। यही मेरा सवाल है। विधि के अंदर और बाहर आने में बिताए गए समय विधि के अंदर उपयोगी काम करने में व्यतीत समय की तुलना में छोटे हो सकते हैं। यदि ऐसा है, तो हो रही है और प्राप्त करने का अनुकूलन केवल थोड़ा, प्रतिशत-वार की मदद कर सकता है। –

+0

मेरा मुद्दा यह है कि यदि विधि स्वयं ही बेहद हल्की थी (एक असाइनमेंट या केवल एक मूल्य लौटाता है) विधि-कॉल के प्रकार का एक बड़ा प्रभाव हो सकता है (कई कॉलों पर एकत्रित)। – Nicole

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