देशी कोड को कॉल करने के लिए JNA के बजाय JNI का उपयोग करें?


115

जेएनआई की तुलना में जेएनए को देशी कोड का उपयोग करना आसान लगता है। आप किन मामलों में JNI का उपयोग JNA पर करेंगे?


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

जवाबों:


126
  1. JNA c ++ क्लासेस की मैपिंग का समर्थन नहीं करता है, इसलिए यदि आप c ++ लाइब्रेरी का उपयोग कर रहे हैं तो आपको jni आवरण की आवश्यकता होगी
  2. यदि आपको मेमोरी कॉपी करने की बहुत आवश्यकता है। उदाहरण के लिए, आप एक विधि को कॉल करते हैं जो आपको एक बड़ा बाइट बफर लौटाता है, आप इसमें कुछ बदलते हैं, फिर आपको एक अन्य विधि कॉल करने की आवश्यकता होती है जो इस बाइट बफर का उपयोग करता है। इसके लिए आपको इस बफ़र को c से java तक कॉपी करना होगा, फिर इसे java से c में वापस कॉपी करना होगा। इस मामले में jni प्रदर्शन में जीत जाएगी क्योंकि आप इस बफ़र को c में रख सकते हैं और संशोधित कर सकते हैं, बिना कॉपी किए।

ये समस्याएं हैं जिनका मैंने सामना किया है। शायद ज्यादा है। लेकिन सामान्य प्रदर्शन में, jna और jni के बीच भिन्न नहीं है, इसलिए जहाँ भी आप JNA का उपयोग कर सकते हैं, उसका उपयोग करें।

संपादित करें

यह उत्तर काफी लोकप्रिय प्रतीत होता है। तो यहाँ कुछ जोड़ हैं:

  1. यदि आपको C ++ या COM को मैप करने की आवश्यकता है, तो ब्रोकरेज नामक जेएनएरेटर के निर्माता ओलिवर शैफिक द्वारा एक पुस्तकालय है । यह अभी भी एक युवा पुस्तकालय है, लेकिन इसमें कई दिलचस्प विशेषताएं हैं:
    • डायनेमिक C / C ++ / COM इंटरॉप: C ++ विधियां कॉल करें, C ++ ऑब्जेक्ट्स बनाएँ (और जावा से सबक्लास C ++ क्लासेस बनाएं!)
    • जेनेरिक के अच्छे उपयोग के साथ सीधा टाइप मैपिंग (पॉइंटर्स के लिए बहुत अच्छे मॉडल सहित)
    • फुल जेनेरेटर सपोर्ट
    • विंडोज, लिनक्स, मैकओएस एक्स, सोलारिस, एंड्रॉइड पर काम करता है
  2. स्मृति की नकल के लिए, मेरा मानना ​​है कि जेएनए सीधे बाइटबफर्स ​​का समर्थन करता है, इसलिए मेमोरी की नकल से बचा जा सकता है।

इसलिए, मेरा अब भी मानना ​​है कि जहाँ भी संभव हो, JNA या ब्रिजेज का उपयोग करना बेहतर है, और यदि प्रदर्शन महत्वपूर्ण है, तो jni में वापस लौटें, क्योंकि यदि आपको अक्सर मूल कार्यों को कॉल करने की आवश्यकता होती है, तो प्रदर्शन हिट ध्यान देने योग्य है।


6
मैं असहमत हूं, जेएनए के पास बहुत ज्यादा उपरि है। हालांकि इसकी सुविधा गैर-महत्वपूर्ण क्रिटिकल कोड
ग्रेगरी पकोस्ज़

3
मैं एक Android परियोजना के लिए BridJ का उपयोग कर, अपने से सीधे उद्धृत करने से पहले सावधानी की सलाह देंगे डाउनलोड पृष्ठ : "BridJ Android पर आंशिक रूप से काम करता है / हाथ emulators (SDK के साथ), और शायद यहां तक कि वास्तविक उपकरणों पर (untested)। "
kizzx2

1
@StockB: यदि आपके पास एपीआई के साथ एक पुस्तकालय है जहां आपको C ++ ऑब्जेक्ट्स को पास करना है, या C ++ ऑब्जेक्ट पर कॉल करने के तरीके हैं, तो JNA ऐसा नहीं कर सकता है। इसे केवल वेनिला सी तरीके कह सकते हैं।
डेनिस तुलस्किए

2
जहां तक ​​मैं समझता हूं, जेएनआई केवल वैश्विक JNIEXPORTकार्यों को बुला सकता है। मैं वर्तमान में एक विकल्प के रूप में JavaCpp की खोज कर रहा हूं, जो जेएनआई का उपयोग करता है, लेकिन मुझे नहीं लगता कि वेनिला जेएनआई इसका समर्थन करता है। क्या वेनिला जेएनआई का उपयोग करके सी ++ सदस्य कार्यों को कॉल करने का एक तरीका है जिसे मैं देख रहा हूं?
StockB

1
कृपया यहां एक नज़र डालें stackoverflow.com/questions/20332472/catch-a-double-hotkey
ッ stack stack stack '

29

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

हालाँकि, मैंने कभी भी किसी भी तरह के मतभेद नहीं किए हैं, मैं डिजाइन के कारण, कम से कम यह मानता हूं कि कुछ स्थितियों में JNA के साथ उस प्रकार का रूपांतरण JNI के साथ और भी बुरा प्रदर्शन करेगा। उदाहरण के लिए, जब सरणियाँ गुजरती हैं, तो JNA प्रत्येक फ़ंक्शन कॉल की शुरुआत में जावा से मूल में और फ़ंक्शन कॉल के अंत में वापस बदल जाएगा। जेएनआई के साथ, आप अपने आप को नियंत्रित कर सकते हैं जब सरणी का एक मूल "दृश्य" उत्पन्न होता है, संभवतः केवल सरणी के एक हिस्से का एक दृश्य बना रहा है, कई फ़ंक्शन कॉल पर दृश्य रखें और अंत में दृश्य को छोड़ दें और यदि आप चाहें तो तय करें परिवर्तनों को रखने के लिए (संभवतः डेटा वापस कॉपी करने के लिए आवश्यक है) या परिवर्तनों को त्यागें (कोई प्रतिलिपि आवश्यक नहीं)। मुझे पता है कि आप मेमोरी क्लास में JNA के साथ फंक्शन कॉल में एक देशी सरणी का उपयोग कर सकते हैं, लेकिन इसके लिए मेमोरी कॉपी करने की भी आवश्यकता होगी, जेएनआई के साथ अनावश्यक हो सकता है। अंतर प्रासंगिक नहीं हो सकता है, लेकिन यदि आपका मूल लक्ष्य मूल कोड में इसके कुछ हिस्सों को लागू करके अनुप्रयोग प्रदर्शन को बढ़ाना है, तो एक खराब प्रदर्शन पुल तकनीक का उपयोग करना सबसे स्पष्ट विकल्प नहीं लगता है।


8
  1. आप JNA से कुछ साल पहले कोड लिख रहे हैं या 1.4 JRE से पहले लक्ष्य कर रहे हैं।
  2. जिस कोड के साथ आप काम कर रहे हैं वह DLL \ SO में नहीं है।
  3. आप उस कोड पर काम कर रहे हैं जो LGPL के साथ असंगत है।

यह केवल वही है जो मैं अपने सिर के ऊपर से आ सकता हूं, हालांकि मैं किसी भी तरह का भारी उपयोगकर्ता नहीं हूं। यह भी लगता है कि आप JNA से बच सकते हैं यदि आप एक बेहतर इंटरफ़ेस चाहते हैं जो वे प्रदान करते हैं लेकिन आप जावा में उसके आसपास कोड कर सकते हैं।


9
मैं 2 के बारे में असहमत हूं - स्टेटिक लीव को डायनामिक लिब में बदलना आसान है। मेरा प्रश्न देखें, यह stackoverflow.com/questions/845183/…
jb है।

3
JNA 4.0 के साथ शुरू, JNA LGPL 2.1 और Apache लाइसेंस 2.0 दोनों के तहत दोहरे लाइसेंस वाला है, और जो आप चुनते हैं वह आपके ऊपर है
sbarber2

8

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


5
इसलिए, एक विधि कॉल के बजाय हमारे पास संदेश पासिंग है। मैंने जेएनआई और जेएनए में काफी समय लगाया है और ब्रिजेज भी, लेकिन बहुत जल्द, वे सभी थोड़ा डरावना हो जाते हैं।
उस्तामान संगत

5

यह एक सीधा जवाब नहीं है और मुझे JNA के साथ कोई अनुभव नहीं है, लेकिन जब मैं JNA का उपयोग करने वाली परियोजनाओं को देखता हूं और SVNKit, IntelliJ IDEA, NetBeans IDE, आदि जैसे नाम देखता हूं, तो मुझे विश्वास है कि यह एक बहुत अच्छा पुस्तकालय है।

वास्तव में, मुझे निश्चित रूप से लगता है कि मैंने जेएनआई के बजाय जेएनए का उपयोग किया होगा जब मुझे वास्तव में जेएनआई (जो उबाऊ विकास प्रक्रिया है) की तुलना में सरल दिखता है। बहुत बुरा, JNA को इस समय जारी नहीं किया गया था।


3

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

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

JANET तब बैकलिक-एम्बेडेड जावा को उपयुक्त JNI कॉल में अनुवादित करता है।


3

मैंने वास्तव में जेएनआई और जेएनए के साथ कुछ सरल बेंचमार्क किए।

जैसा कि दूसरों ने पहले ही बताया है, जेएनए सुविधा के लिए है। JNA का उपयोग करते समय आपको मूल कोड संकलित करने या लिखने की आवश्यकता नहीं है। जेएनए का मूल पुस्तकालय लोडर भी मैंने कभी देखा है उपयोग करने के लिए सबसे अच्छा / आसान में से एक है। अफसोस की बात है, आप इसे जेएनआई के लिए उपयोग नहीं कर सकते हैं ऐसा लगता है। (यही कारण है कि मैंने System.loadLibrary () के लिए एक विकल्प लिखा है जो JNA के पथ सम्मेलन का उपयोग करता है और क्लासपैथ (यानी जार) से निर्बाध लोडिंग का समर्थन करता है।

हालांकि, JNA का प्रदर्शन JNI की तुलना में बहुत खराब हो सकता है। मैंने एक बहुत ही सरल परीक्षण किया, जिसे एक साधारण देशी पूर्णांक वृद्धि फ़ंक्शन "रिटर्न आर्ग + 1" कहा जाता है। जेएमएच के साथ किए गए बेंचमार्क ने दिखाया कि जेएनआई उस फ़ंक्शन को जेएनए से 15 गुना तेज है।

एक अधिक "जटिल" उदाहरण जहां मूल फ़ंक्शन 4 मानों के पूर्णांक सरणी को प्रस्तुत करता है फिर भी पता चलता है कि जेएनआई का प्रदर्शन जेएनए से 3 गुना तेज है। कम लाभ संभवत: इस वजह से था कि आप जेएनआई में सरणियों का उपयोग कैसे करते हैं: मेरे उदाहरण ने कुछ सामान बनाया और प्रत्येक संक्षिप्त ऑपरेशन के दौरान इसे फिर से जारी किया।

कोड और परीक्षण के परिणाम जीथब में पाए जा सकते हैं ।


2

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


1

जब तक मुझे कुछ याद नहीं आ रहा है, तब तक JNA बनाम JNI के बीच मुख्य अंतर नहीं है कि JNA के साथ आप मूल (C) कोड से जावा कोड को कॉल नहीं कर सकते?


6
आप ऐसा कर सकते हैं। एक कॉलबैक वर्ग के साथ जो सी तरफ एक फ़ंक्शन पॉइंटर से मेल खाती है। void register_callback (void (*) (const int)); सार्वजनिक स्थिर देशी शून्य register_callback (MyCallback arg1) में मैप किया जाएगा; जहाँ MyCallback एक इंटरफ़ेस है, जो com.sun.jna का विस्तार करता है। एकल विधि शून्य (लागू मान) के साथ कॉलबैक;
उस्मान संगत

@ ऑगस्टो यह एक टिप्पणी भी हो सकती है
स्विफ्टबॉय 12

0

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

  1. DllMain (विंडोज के साथ इंटरफेस करने के लिए आवश्यक)
  2. OnLoad (बस एक OutputDebugString करता है ताकि मुझे पता चल सके कि जावा कोड कब संलग्न है)
  3. OnUnload (डिट्टो)
  4. खोलें (पोर्ट खोलता है, थ्रेड पढ़ना और लिखना शुरू करता है)
  5. QueueMessage (लेखन थ्रेड द्वारा आउटपुट के लिए कतार डेटा)
  6. GetMessage (अंतिम कॉल के बाद रीड थ्रेड द्वारा प्राप्त डेटा की प्रतीक्षा और रिटर्न करता है)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.