c++ - स्थिर लिंकिंग बनाम गतिशील लिंकिंग




performance static-linking (10)

1 / मैं उन परियोजनाओं पर रहा हूं जहां डायनामिक लिंकिंग बनाम स्थैतिक लिंकिंग बेंचमार्क किया गया था और अंतर गतिशील लिंकिंग पर स्विच करने के लिए पर्याप्त छोटा नहीं था (मैं परीक्षण का हिस्सा नहीं था, मुझे बस निष्कर्ष पता है)

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

3 / मैं अन्य परियोजनाओं पर रहा हूं जो "आसान पैच" सुविधा के लिए गतिशील लिंकिंग का उपयोग करते हैं। लेकिन यह "आसान पैच" छोटे फिक्स का वितरण थोड़ा आसान और जटिल संस्करण का एक दुःस्वप्न बनाता है। हम अक्सर ग्राहक साइट पर समस्याओं को ट्रैक करने के लिए सब कुछ धक्का देकर समाप्त हो गए क्योंकि गलत संस्करण टोकन था।

मेरा निष्कर्ष यह है कि मैं स्थिर लिंकिंग का उपयोग करता हूं:

  • प्लगइन जैसी चीजों के लिए जो गतिशील लिंकिंग पर निर्भर करता है

  • जब साझा करना महत्वपूर्ण होता है (सी / सी ++ रनटाइम, जीयूआई पुस्तकालयों, जैसे कई प्रक्रियाओं द्वारा उपयोग की जाने वाली बड़ी लाइब्रेरी ... जिन्हें अक्सर स्वतंत्र रूप से प्रबंधित किया जाता है और जिसके लिए एबीआई सख्ती से परिभाषित किया जाता है)

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

क्या गतिशील लिंकिंग या कुछ स्थितियों में इसके विपरीत स्थिर लिंकिंग चुनने के लिए कोई आकर्षक प्रदर्शन कारण हैं? मैंने निम्नलिखित सुना है या पढ़ा है, लेकिन मुझे इस विषय पर पर्याप्तता नहीं है कि इसकी सत्यता के लिए झुकाव हो।

1) स्थिर लिंकिंग और गतिशील लिंकिंग के बीच रनटाइम प्रदर्शन में अंतर आमतौर पर नगण्य है।

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


1) इस तथ्य पर आधारित है कि एक डीएलएल समारोह को कॉल करना हमेशा एक अतिरिक्त अप्रत्यक्ष कूद का उपयोग कर रहा है। आज, यह आमतौर पर नगण्य है। डीएलएल के अंदर i386 CPU पर कुछ और ओवरहेड है, क्योंकि वे स्थिति स्वतंत्र कोड उत्पन्न नहीं कर सकते हैं। Amd64 पर, कूद काउंटर प्रोग्राम काउंटर के सापेक्ष हो सकते हैं, इसलिए यह एक बड़ा सुधार है।

2) यह सही है। प्रोफाइलिंग द्वारा निर्देशित अनुकूलन के साथ आप आमतौर पर लगभग 10-15 प्रतिशत प्रदर्शन जीत सकते हैं। अब जब सीपीयू की गति इसकी सीमा तक पहुंच गई है तो यह करने के लायक हो सकता है।

मैं जोड़ूंगा: (3) लिंकर अधिक कैश कुशल समूह में फ़ंक्शंस व्यवस्थित कर सकता है, ताकि महंगा कैश स्तर की यादें कम हो जाएं। यह विशेष रूप से अनुप्रयोगों के स्टार्टअप समय को भी प्रभावित कर सकता है (परिणाम जो मैंने सूर्य सी ++ कंपाइलर के साथ देखा है)

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

इन कारणों से, यदि डीएलएल के लिए कोई वास्तविक आवश्यकता नहीं है, तो केवल स्थिर संकलन का उपयोग करें।

संपादित करें (उपयोगकर्ता अंडरस्कोर द्वारा टिप्पणी का जवाब देने के लिए)

स्वतंत्र कोड समस्या की स्थिति के बारे में यहां एक अच्छा संसाधन है http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

जैसा कि बताया गया है कि x86 में उन्हें किसी और चीज के लिए AFAIK नहीं है, तो 15 बिट कूद सीमाएं हैं और बिना शर्त कूद और कॉल के लिए। Thats क्यों (जेनरेटर से) 32k अधिक होने के बाद हमेशा एक समस्या है और एम्बेडेड trampolines की जरूरत है।

लेकिन लिनक्स की तरह लोकप्रिय x86 ओएस पर आपको केवल देखभाल करने की आवश्यकता नहीं है अगर एसओ / डीएलएल फ़ाइल gcc स्विच- -fpic (जो अप्रत्यक्ष जंप टेबल के उपयोग को लागू करती है) के साथ उत्पन्न नहीं होती है। क्योंकि यदि आप नहीं करते हैं, तो कोड बस एक सामान्य लिंकर की तरह तय किया जाएगा, इसे स्थानांतरित कर देगा। लेकिन ऐसा करने पर यह कोड सेगमेंट को साझा करने योग्य नहीं बनाता है और इसे डिस्क से कोड में पूर्ण मैपिंग की आवश्यकता होगी और इसे इस्तेमाल करने से पहले इसे छूने की आवश्यकता होगी (अधिकांश कैशों को खाली करना, टीएलबी को मारना आदि)। एक समय था जब इसे धीमा माना जाता था ... बहुत धीमा।

तो अब आपको कोई फायदा नहीं होगा।

मुझे याद नहीं है कि ओएस (सोलारिस या फ्रीबीएसडी) ने मुझे अपने यूनिक्स बिल्ड सिस्टम के साथ समस्याएं दीं क्योंकि मैं बस ऐसा नहीं कर रहा था और सोच रहा था कि जब तक मैं लागू नहीं करता तब तक यह क्रैश क्यों हुआ।


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

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

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


गतिशील लिंकिंग को ओएस के लिए गतिशील पुस्तकालय खोजने और इसे लोड करने के लिए अतिरिक्त समय की आवश्यकता होती है। स्थिर लिंकिंग के साथ, सब कुछ एक साथ है और यह स्मृति में एक शॉट शॉट है।

इसके अलावा, डीएलएल नरक देखें। यह वह परिदृश्य है जहां ओएस लोड करने वाला डीएलएल वह नहीं है जो आपके आवेदन के साथ आया था, या वह संस्करण जो आपके आवेदन की अपेक्षा करता है।


प्रणालियों की एक विशाल और बढ़ती संख्या है जहां स्थिर लिंकिंग का एक चरम स्तर अनुप्रयोगों और सिस्टम के प्रदर्शन पर एक बहुत ही सकारात्मक प्रभाव डाल सकता है।

मैं अक्सर "एम्बेडेड सिस्टम" कहलाता हूं, जिनमें से कई अब सामान्य उद्देश्य वाले ऑपरेटिंग सिस्टम का उपयोग कर रहे हैं, और इन प्रणालियों का उपयोग कल्पनाशील सब कुछ के लिए किया जाता है।

Busybox का उपयोग कर जीएनयू / लिनक्स सिस्टम का उपयोग कर एक बेहद आम उदाहरण डिवाइस हैं। मैंने इसे बूट करने योग्य i386 (32-बिट) सिस्टम छवि बनाकर NetBSD साथ चरम पर ले लिया है जिसमें कर्नेल और इसकी रूट फाइल सिस्टम दोनों शामिल हैं, बाद वाले में हार्ड-लिंक वाले एक स्थिर-जुड़े ( crunchgen द्वारा) बाइनरी शामिल है मानक पूर्ण-सुविधा प्रणाली कार्यक्रमों (टूलचैन को छोड़कर सबसे अधिक) के सभी कार्यक्रमों में ( सभी को अंतिम गिनती 274) में शामिल किया गया है, और यह आकार में 20 मेगा बाइट से भी कम है (और संभवतः केवल सिस्टम में बहुत ही आराम से चलता है 64 एमबी मेमोरी (रूट फाइल सिस्टम के साथ भी असंपीड़ित और पूरी तरह से रैम में), हालांकि मैं इसे परीक्षण करने के लिए एक छोटा सा खोजने में असमर्थ हूं)।

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

हालांकि यह अभी भी पूरी कहानी नहीं है। मैं आमतौर पर नेटबीएसडी ऑपरेटिंग सिस्टम का निर्माण और उपयोग करता हूं, जो कि मेरे पूर्ण विकास प्रणालियों के लिए सभी बाइनरी को स्थिर-लिंक करके स्थापित करता है। भले ही इसमें अधिक मात्रा में डिस्क स्पेस (~ 6.6 जीबी कुल x86_64 के लिए टूलकैन और एक्स 11 स्टेटिक-लिंक्ड सहित) लेता है (विशेष रूप से यदि कोई अन्य प्रोग्राम के लिए पूर्ण डीबग प्रतीक टेबल उपलब्ध कराता है तो ~ 2.5GB), परिणाम अभी भी कुल मिलाकर तेजी से चलता है, और कुछ कार्यों के लिए लाइब्रेरी कोड पृष्ठों को साझा करने के लिए एक सामान्य गतिशील-लिंक सिस्टम से भी कम स्मृति का उपयोग करता है। डिस्क सस्ता है (यहां तक ​​कि तेज डिस्क), और अक्सर उपयोग की जाने वाली डिस्क फ़ाइलों को कैश करने की स्मृति भी अपेक्षाकृत सस्ता है, लेकिन सीपीयू चक्र वास्तव में नहीं हैं, और प्रत्येक प्रक्रिया के लिए ld.so स्टार्टअप लागत का भुगतान करना हर बार शुरू होता है, सीपीयू चक्रों के घंटों को उन कार्यों से दूर किया जाता है जिन्हें कई प्रक्रियाएं शुरू करने की आवश्यकता होती है, विशेष रूप से जब एक ही कार्यक्रम का उपयोग किया जाता है, जैसे विकास प्रणाली पर कंपाइलर्स। स्टेटिक-लिंक्ड टूलचेन प्रोग्राम घंटों तक मेरे सिस्टम के लिए पूरे-ओएस मल्टी-आर्किटेक्चर बिल्ड टाइम्स को कम कर सकते हैं। मैंने अभी तक अपने सिंगल crunchgen 'एड बाइनरी में crunchgen का निर्माण नहीं किया है, लेकिन मुझे संदेह है कि जब मैं करता हूं तो सीपीयू कैश के लिए जीत के कारण बिल्ड समय crunchgen


मैं अंक dnmckee उल्लेखों के साथ सहमत हैं, प्लस:

  • स्थैतिक रूप से जुड़े अनुप्रयोगों को तैनात करना आसान हो सकता है, क्योंकि कम या कोई अतिरिक्त फ़ाइल निर्भरता (.dll / .so) है जो गलत जगह पर अनुपलब्ध या स्थापित होने पर समस्याएं पैदा कर सकती है।

यूनिक्स जैसी प्रणालियों पर, डायनामिक लिंकिंग 'रूट' के लिए जीवन को कठिन तरीके से किसी भी तरह के स्थानों में स्थापित साझा पुस्तकालयों के साथ उपयोग करने के लिए कठिन बना सकती है। ऐसा इसलिए है क्योंकि डायनामिक लिंकर आम तौर पर रूट विशेषाधिकारों के साथ प्रक्रियाओं के लिए LD_LIBRARY_PATH या उसके समकक्ष पर ध्यान नहीं देगा। कभी-कभी, स्थिर लिंकिंग दिन बचाता है।

वैकल्पिक रूप से, स्थापना प्रक्रिया को पुस्तकालयों का पता लगाना पड़ता है, लेकिन यह सॉफ़्टवेयर के एकाधिक संस्करणों के लिए मशीन पर सह-अस्तित्व में मुश्किल हो सकता है।


स्टेटिक लिंकिंग में उन फ़ाइलों को शामिल किया गया है जिन्हें प्रोग्राम को एक निष्पादन योग्य फ़ाइल में चाहिए।

डायनामिक लिंकिंग वह है जिसे आप सामान्य मानते हैं, यह निष्पादन योग्य बनाता है जिसे अभी भी डीएलएल की आवश्यकता होती है और ऐसी ही निर्देशिका में होना (या डीएलएल सिस्टम फ़ोल्डर में हो सकता है)।

(डीएलएल = गतिशील लिंक लाइब्रेरी)

गतिशील रूप से जुड़े निष्पादन योग्य तेज़ी से संकलित किए जाते हैं और संसाधन-भारी नहीं होते हैं।


This लिनक्स और प्रदर्शन प्रत्यारोपण पर साझा पुस्तकालयों के बारे में बहुत विस्तार से चर्चा करता है।


LGPL जैसी कुछ लाइसेंस आवश्यकताओं को पूरा करने का एकमात्र व्यावहारिक तरीका डायनामिक लिंकिंग है।





dynamic-linking