जेएनआई कॉल क्या धीमा करता है?


194

मुझे पता है कि जावा में जेएनआई कॉल करते समय 'सीमाएँ पार करना' धीमा है।

हालाँकि मैं जानना चाहता हूं कि ऐसा क्या है जो इसे धीमा बनाता है? जेएनआई कॉल करते समय अंतर्निहित जेवीएम कार्यान्वयन क्या करता है जो इसे इतना धीमा बनाता है?


2
(+1) अच्छा सवाल। जब हम इस विषय पर होते हैं, तो मैं किसी को भी प्रोत्साहित करना चाहूंगा जिन्होंने अपने निष्कर्षों को पोस्ट करने के लिए वास्तविक बेंचमार्क किए हैं।
एनपीई

2
एक JNI कॉल को C (उदाहरण के लिए) को समझने के लिए पारित जावा वस्तुओं को बदलने की जरूरत है; वापसी मूल्य के साथ भी। टाइप कन्वर्जन और कॉल स्टैक मार्शलिंग इसका एक अच्छा हिस्सा हैं।
डेव न्यूटन

डेव, मैं समझता हूं और इसके बारे में पहले सुना है। लेकिन क्या वास्तव में रूपांतरण की तरह है? वह 'कुछ ’क्या है? मैं विवरण की तलाश में हूं।
pdeva

जावा और सी के बीच डेटा पास करने के लिए सीधे बाइटबफर्स ​​का उपयोग करने के परिणामस्वरूप अपेक्षाकृत कम ओवरहेड हो सकता है।
पीटर लॉरी

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

जवाबों:


174

सबसे पहले, यह ध्यान देने योग्य है कि "धीमी गति से," हम कुछ ऐसी चीजों के बारे में बात कर रहे हैं जो दसियों नैनोसेकंड ले सकते हैं। तुच्छ देशी तरीकों के लिए, 2010 में मैंने अपने विंडोज डेस्कटॉप पर औसतन 40 ns और मेरे मैक डेस्कटॉप पर 11 ns पर कॉल को मापा। जब तक आप कई कॉल नहीं कर रहे हैं, आप नोटिस नहीं करेंगे।

उस ने कहा, एक सामान्य जावा विधि कॉल करने की तुलना में एक देशी विधि कॉलिंग धीमी हो सकती है । कारणों में शामिल हैं:

  • JVM द्वारा मूल तरीकों को इनलाइन नहीं किया जाएगा। न ही वे इस विशिष्ट मशीन के लिए संकलित समय-समय पर होंगे - वे पहले से ही संकलित हैं।
  • एक जावा सरणी को मूल कोड में एक्सेस के लिए कॉपी किया जा सकता है, और बाद में वापस कॉपी किया जा सकता है। सरणी के आकार में लागत रैखिक हो सकती है। मैंने अपने विंडोज डेस्कटॉप पर 75 माइक्रोसेकंड और मैक पर 82 माइक्रोसेकंड औसत करने के लिए 100,000 सरणी की जेएनआई कॉपी की माप की । सौभाग्य से, GetPrimitiveArrayCritical या NewDirectByteBuffer के माध्यम से सीधे पहुंच प्राप्त की जा सकती है ।
  • यदि विधि एक ऑब्जेक्ट पास की जाती है, या कॉलबैक करने की आवश्यकता होती है, तो मूल विधि संभवतः जेवीएम को अपनी कॉल कर रही है। मूल कोड से जावा फ़ील्ड, विधियों और प्रकारों तक पहुंचने के लिए प्रतिबिंब के समान कुछ की आवश्यकता होती है। हस्ताक्षर तार में निर्दिष्ट होते हैं और जेवीएम से क्वियर होते हैं। यह धीमा और त्रुटि-प्रवण दोनों है ।
  • जावा स्ट्रिंग्स ऑब्जेक्ट हैं, लंबाई है और एन्कोडेड हैं। स्ट्रिंग तक पहुँचने या बनाने के लिए O (n) कॉपी की आवश्यकता हो सकती है।

कुछ अतिरिक्त चर्चा, संभवतः दिनांकित, "जावा Performance प्लेटफॉर्म प्रदर्शन: रणनीतियाँ और रणनीति", 2000 में, स्टीव विल्सन और जेफ केसलमैन द्वारा, "9.2: एग्जामिनिंग जेएनआई कॉस्ट" में पाया जा सकता है। यह इस पृष्ठ के तीसरे भाग के बारे में है , जो नीचे @Philip द्वारा टिप्पणी में प्रदान किया गया है।

2009 आईबीएम डेवलपरवॉक पेपर "जावा नेटिव इंटरफ़ेस का उपयोग करने के लिए सर्वोत्तम अभ्यास" जेएनआई के साथ प्रदर्शन की गड़बड़ी से बचने के लिए कुछ सुझाव प्रदान करता है।


1
यह उत्तर दावा करता है, कि जेवीएम द्वारा कुछ मूल कोड को झुकाया जा सकता है।
एएच

5
यह जवाब देता है कि कुछ मानक मूल कोड जेएनआई का उपयोग करने के बजाय जेवीएम में अंतर्निर्मित हैं। ऊपर, "देशी तरीके" जेएनआई के माध्यम से कार्यान्वित उपयोगकर्ता-परिभाषित देशी तरीकों के सामान्य मामले को संदर्भित करता है। सूचक के लिए धन्यवाद sun.misc.Unsafe।
एंडी थॉमस

मैं यह दावा नहीं करना चाहता था, कि इस दृष्टिकोण का उपयोग हर JNI कॉल के लिए किया जा सकता है। लेकिन यह पता चला है कि वहाँ चोट नहीं होगा है शुद्ध बाईटकोड और शुद्ध JNI कोड के बीच कुछ बीच मैदान। शायद यह कुछ डिज़ाइन निर्णयों को प्रभावित करेगा। शायद यह तंत्र भविष्य में सामान्यीकृत है।
एएच

3
@ हां, आप आंतरिक w / JNI की गलती करते हैं। वे काफी अलग हैं। sun.misc.Unsafeऔर System.currentTimeMillis/nanoTimeजेवीएम द्वारा 'जादू' के माध्यम से अन्य सामान की तरह काफी कुछ संभाला जाता है। वे JNI नहीं हैं और उनके पास उचित .c / .h फाइलें नहीं हैं, जो JVM के निहितार्थ को रोकती हैं। जब तक आप JVM लिख / हैक नहीं कर रहे हैं तब तक इस दृष्टिकोण का पालन नहीं किया जा सकता है।
बेस्टसेन

1
" यह java.sun.com दस्तावेज़ " वर्तमान में टूट गया है - यहाँ एक काम कर रहा लिंक है।
फिलिप गिनी

25

यह ध्यान देने योग्य है कि सभी जावा विधियाँ native"धीमी" नहीं हैं। उनमें से कुछ आंतरिक हैं जो उन्हें बहुत तेज बनाते हैं। यह जांचने के लिए कि कौन से आंतरिक हैं और कौन से नहीं हैं, आप vmSymbols.hppdo_intrinsic पर देख सकते हैं ।


23

मूल रूप से JVM व्याख्यात्मक रूप से प्रत्येक JNI कॉल के लिए C मापदंडों का निर्माण करता है और कोड अनुकूलित नहीं है।

इस पत्र में उल्लिखित कई और विवरण हैं

यदि आप जेएनआई बनाम देशी कोड बेंचमार्किंग में रुचि रखते हैं तो इस परियोजना में बेंचमार्क चलाने के लिए कोड है।


2
आप जिस पेपर से जुड़े हैं, वह एक प्रदर्शन बेंचमार्क पेपर की तरह लगता है जो बताता है कि जेएनआई आंतरिक रूप से कैसे काम करता है।
pdeva

@pdeva दुर्भाग्य से मुझे मिले अन्य संसाधन java.sun.com से जुड़े थे और Oracle अधिग्रहण के बाद से लिंक अपडेट नहीं हुए हैं। मैं जेएनआई इंटर्नल्स के बारे में अधिक जानकारी की तलाश कर रहा हूं।
dmck

13
पेपर जावा 1.3 के बारे में है - काफी समय पहले। क्या उस समय के मुद्दे अभी भी जावा 7 पर लागू होते हैं?
एएच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.