سؤال

هل هناك أي أسباب مقنعة للأداء لاختيار الربط الثابت على الارتباط الديناميكي أو العكس في مواقف معينة؟ لقد سمعت أو قرأت ما يلي ، لكنني لا أعرف ما يكفي من الموضوع لتضمينه على صدقه.

1) الفرق في أداء وقت التشغيل بين الربط الثابت والربط الديناميكي عادة ما يكون ضئيلًا.

2) (1) ليس صحيحًا إذا كان استخدام برنامج التحويل البرمجي الذي يستخدم بيانات الملف الشخصي لتحسين مسارات البرنامج لأنه مع الارتباط الثابت ، يمكن للمترجم تحسين كل من الرمز ورمز المكتبة. مع الارتباط الديناميكي فقط يمكن تحسين الكود الخاص بك. إذا تم قضاء معظم الوقت في تشغيل رمز المكتبة ، فقد يحدث هذا فرقًا كبيرًا. خلاف ذلك ، (1) لا يزال ينطبق.

هل كانت مفيدة؟

المحلول

  • متحرك الربط العلبة تقليل إجمالي استهلاك الموارد (إذا كانت أكثر من عملية تشترك في نفس المكتبة (بما في ذلك الإصدار في "نفس" ، بالطبع)). أعتقد أن هذه هي الحجة التي تدفعها إلى وجودها في معظم البيئات. هنا "الموارد" تشمل مساحة القرص ، وذاكرة الوصول العشوائي ، ومساحة ذاكرة التخزين المؤقت. بالطبع ، إذا كان الرابط الديناميكي الخاص بك غير مرن بدرجة كافية ، فهناك خطر من DLL الجحيم.
  • متحرك الارتباط يعني أن إصلاحات الأخطاء وترقياتها للمكتبات بث لتحسين لك المنتج دون مطالمك بشحن أي شيء.
  • الإضافات دائما دعوة متحرك الربط.
  • ثابتة الارتباط ، يعني أنه يمكنك معرفة الرمز الذي سيتم تشغيله بشكل كبير بيئات محدودة (في وقت مبكر من عملية التمهيد ، أو في وضع الإنقاذ).
  • ثابتة الربط يمكن أن يصنع الثنائيات أسهل في التوزيع إلى بيئات المستخدم المتنوعة (على حساب إرسال برنامج جائع أكبر وأكثر موارد).
  • ثابتة الارتباط قد يسمح قليلا بدء التشغيل بشكل أسرع مرات ، ولكن هذا يعتمد إلى حد ما على كل من حجم وتعقيد البرنامج الخاص بك و على تفاصيل استراتيجية تحميل نظام التشغيل.

بعض التعديلات لتشمل الاقتراحات ذات الصلة للغاية في التعليقات وفي إجابات أخرى. أود أن ألاحظ أن الطريقة التي تفكك بها هذا تعتمد كثيرًا على البيئة التي تخطط لتشغيلها. قد لا يكون للأنظمة المدمجة الحد الأدنى موارد كافية لدعم الارتباط الديناميكي. قد تدعم أنظمة صغيرة أكبر قليلاً الربط الديناميكي ، لأن ذاكرتها صغيرة بما يكفي لجعل توفير ذاكرة الوصول العشوائي من الارتباط الديناميكي جذاب للغاية. تحتوي أجهزة الكمبيوتر الاستهلاكية الكاملة ، كما يلاحظ مارك ، على موارد هائلة ، وربما يمكنك السماح للمشكلات الراحة بقيادة تفكيرك في هذا الأمر.


لمعالجة مشكلات الأداء والكفاءة: هذا يعتمد.

من الناحية الكلاسيكية ، تتطلب المكتبات الديناميكية نوعًا من طبقة الغراء التي تعني غالبًا الإرسال المزدوج أو طبقة إضافية من الاتجاه في معالجة الوظائف ويمكن أن تكلف سرعة صغيرة (ولكن وقت الاتصال بالوظيفة جزءًا كبيرًا من وقت التشغيل ؟؟؟).

ومع ذلك ، إذا كنت تقوم بتشغيل عمليات متعددة تسميها جميعها نفس المكتبة كثيرًا ، فيمكنك في النهاية حفظ خطوط ذاكرة التخزين المؤقت (وبالتالي الفوز في تشغيل الأداء) عند استخدام الارتباط الديناميكي بالنسبة لاستخدام الربط الثابت. (ما لم تكن نظام التشغيل الحديث ذكيًا بما يكفي لإشعار شرائح متطابقة في الثنائيات المرتبطة بشكل ثابت. يبدو من الصعب ، أي شخص يعلم؟)

قضية أخرى: وقت التحميل. أنت تدفع تكاليف التحميل في مرحلة ما. عندما تدفع هذه التكلفة يعتمد على كيفية عمل نظام التشغيل وكذلك ما الذي تستخدمه. ربما تفضل تأجيل دفعه حتى تعرف أنك بحاجة إليه.

لاحظ أن الربط الثابت-VS-Dynamic هو تقليديًا ليس مشكلة التحسين ، لأن كلاهما ينطوي على تجميع منفصل لأسفل إلى ملفات الكائنات. ومع ذلك ، فإن هذا غير مطلوب: يمكن للمترجم من حيث المبدأ ، "تجميع" المكتبات الثابتة "إلى نموذج AST المهضم في البداية ، و" ربطها "بإضافة تلك ASTS إلى تلك التي تم إنشاؤها للرمز الرئيسي ، وبالتالي تمكين التحسين العالمي. لا يوجد أي من الأنظمة التي أستخدمها تفعل ذلك ، لذلك لا يمكنني التعليق على مدى نجاحها.

طريقة الإجابة على أسئلة الأداء هي دائماً عن طريق الاختبار (واستخدم بيئة اختبار مثل بيئة النشر قدر الإمكان).

نصائح أخرى

1) يعتمد على حقيقة أن استدعاء وظيفة DLL يستخدم دائمًا قفزة غير مباشرة إضافية. اليوم ، هذا عادة ما يكون ضئيلا. يوجد داخل DLL بعض النفقات العامة على وحدة المعالجة المركزية I386 ، لأنهم لا يستطيعون إنشاء رمز مستقل للموضع. في AMD64 ، يمكن أن تكون القفزات بالنسبة إلى عداد البرنامج ، لذلك هذا تحسن كبير.

2) هذا صحيح. مع التحسينات التي تسترشد بها التنميط ، يمكنك عادةً الفوز بحوالي 10-15 في المائة. الآن بعد أن وصلت سرعة وحدة المعالجة المركزية إلى حدودها ، قد يكون الأمر يستحق القيام بذلك.

أود أن أضيف: (3) يمكن للرابط ترتيب الوظائف في تجميع أكثر كفاءة في ذاكرة التخزين المؤقت ، بحيث يتم تقليل مستوى ذاكرة التخزين المؤقت باهظة الثمن. قد يؤثر أيضًا بشكل خاص على وقت بدء التشغيل للتطبيقات (استنادًا إلى النتائج التي رأيتها مع برنامج التحويل البرمجي C ++)

ولا تنسى أنه مع عدم إجراء إزالة الكود الميت DLL. اعتمادًا على اللغة ، قد لا يكون رمز DLL على النحو الأمثل أيضًا. تكون الوظائف الافتراضية ظاهرية دائمًا لأن المترجم لا يعرف ما إذا كان العميل يكتبه.

لهذه الأسباب ، في حالة عدم وجود حاجة حقيقية إلى DLL ، ثم استخدم التجميع الثابت.

تحرير (للإجابة على التعليق ، بواسطة المستخدم المؤكد)

إليك مورد جيد حول مشكلة الكود المستقل في الموقف http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-nibraries/

كما هو موضح X86 ، لا تجعلهم afaik لأي شيء آخر ثم نطاقات قفزة 15 بت وليس للقفزات والمكالمات غير المشروطة. ولهذا السبب كانت الوظائف (من المولدات) التي تزيد عن 32 ألفًا مشكلة دائمًا وتحتاج إلى الترامبولين المدمجة.

ولكن على نظام التشغيل X86 الشهير مثل Linux ، لا تحتاج فقط إلى الاهتمام إذا لم يتم إنشاء ملف SO/DLL مع gcc تحول -fpic (الذي يفرض استخدام جداول القفز غير المباشرة). لأنه إذا لم تقم بذلك ، فسيتم إصلاح الكود فقط مثل الرابط العادي الذي سينقله. ولكن أثناء القيام بذلك ، فإنه يجعل قطاع الكود غير قابل للمشاركة وسيحتاج إلى رسم خرائط كامل للرمز من القرص إلى الذاكرة ولمسه جميعًا قبل استخدامه (إفراغ معظم ذاكرة التخزين المؤقت ، وضرب TLB) وما إلى ذلك. كان هناك وقت عندما كان هذا يعتبر بطيئًا ... بطيئًا جدًا.

لذلك لن يكون لديك أي فائدة بعد الآن.

لا أتذكر ما الذي أعطاني OS (Solaris أو Freebsd) مشاكل مع نظام بناء UNIX الخاص بي لأنني لم أكن أفعل هذا وتساءلت عن سبب تحطمها حتى تقدمت بطلب -fPIC ل gcc.

الارتباط الديناميكي هو الطريقة العملية الوحيدة لتلبية بعض متطلبات الترخيص مثل LGPL.

وأنا أتفق مع النقاط التي يذكرها dnmckee ، بالإضافة إلى:

  • قد يكون النشر أسهل في نشر التطبيقات المرتبطة بشكل ثابت ، نظرًا لوجود تبعيات إضافية للملفات (.DLL / .SO) التي قد تسبب مشاكل عندما تكون مفقودة أو مثبتة في المكان الخطأ.

أحد أسباب القيام ببناء مرتبط بشكل ثابت هو التحقق من أن لديك إغلاقًا تامًا للتنفيذ ، أي أن جميع مراجع الرموز يتم حلها بشكل صحيح.

كجزء من نظام كبير تم بناؤه واختباره باستخدام التكامل المستمر ، تم إجراء اختبارات الانحدار الليلي باستخدام نسخة مرتبطة بشكل ثابت من التنفيذيين. في بعض الأحيان ، نرى أن الرمز لن يحل وأن الرابط الثابت سيفشل على الرغم من أن القابل للتنفيذ المرتبط ديناميكيًا سوف يرتبط بنجاح.

كان هذا عادة ما يحدث عندما كانت الرموز التي كانت جالسة عميقة داخل LIBs المشتركة لها اسم أخطاء إملائي ، وبالتالي لن ترتبط بشكل ثابت. لا يحل الرابط الديناميكي جميع الرموز تمامًا ، بغض النظر عن استخدام التقييم الأول للعمق أو العرض الأول ، حتى تتمكن من الانتهاء من تنفيذ مرتبط ديناميكيًا لا يحتوي على إغلاق كامل.

1/ لقد كنت في المشاريع التي تم فيها تحديد المركز للربط الديناميكي مقابل الربط الثابت ولم يتم تحديد الفرق صغيرًا بما يكفي للتبديل إلى الارتباط الديناميكي (لم أكن جزءًا من الاختبار ، فأنا أعرف الاستنتاج) فقط

2/ يرتبط الارتباط الديناميكي غالبًا بالموافقة المسبقة عن علم (الرمز المستقل للموضع ، رمز لا يلزم تعديله وفقًا للعنوان الذي يتم تحميله فيه). اعتمادًا على الموافقة المسبقة عن علم بالعمارة ، قد يجلب الموافقة المسبقة عن علم إلى تباطؤ آخر ولكن هناك حاجة إليه من أجل الحصول على الاستفادة من مشاركة مكتبة مرتبطة ديناميكيًا بين اثنين قابلة للتنفيذ (وحتى عمليتين من نفس المنافسة إذا كان نظام التشغيل يستخدم العشوائية لعنوان التحميل كتدبير أمان). لست متأكدًا من أن جميع نظام التشغيل يسمح بفصل المفهومين ، لكن Solaris و Linux Do و ISTR أن HP-UX يفعل ذلك أيضًا.

3/ لقد كنت في مشاريع أخرى استخدمت الربط الديناميكي لميزة "Seady Patch". ولكن هذا "التصحيح السهل" يجعل توزيع الإصلاح الصغير أسهل قليلاً ومعقدة كابوس الإصدار. غالبًا ما انتهى بنا الأمر من خلال الاضطرار إلى دفع كل شيء بالإضافة إلى حاجة إلى تتبع المشكلات في موقع العميل لأن الإصدار الخطأ كان رمزًا.

استنتاجي هو أنني كنت أستخدم الارتباط الثابت باستثناء:

  • لأشياء مثل الإضافات التي تعتمد على الربط الديناميكي

  • عندما تكون المشاركة مهمة (مكتبات كبيرة تستخدمها عمليات متعددة في نفس الوقت مثل وقت تشغيل C/C ++ ، ومكتبات واجهة المستخدم الرسومية ، ... والتي غالبًا ما تتم إدارتها بشكل مستقل والتي يتم تعريف ABI بشكل صارم)

إذا أراد المرء استخدام "التصحيح السهل" ، فأنا أزعم أن المكتبات يجب أن تدار مثل المكتبات الكبيرة المذكورة أعلاه: يجب أن تكون مستقلة تقريبًا مع ABI المحددة التي يجب ألا يتم تغييرها عن طريق الإصلاحات.

هذه ناقش بتفصيل كبير حول المكتبات المشتركة حول الآثار المترتبة على Linux والأداء.

وهو بسيط جدا في الحقيقة. عندما تقوم بإجراء تغيير في رمز المصدر الخاص بك ، هل تريد الانتظار لمدة 10 دقائق حتى يتم إنشاءه أو 20 ثانية؟ عشرين ثانية هو كل ما يمكنني تحمله. علاوة على ذلك ، إما أن أخرج السيف أو أبدأ في التفكير في كيفية استخدام تجميع منفصل وربطه لإعادته إلى منطقة الراحة.

على الأنظمة الشبيهة بـ UNIX ، يمكن أن تجعل الارتباط الديناميكي أمرًا صعبًا على "الجذر" لاستخدام تطبيق مع المكتبات المشتركة المثبتة في مواقع خارجية. وذلك لأن الرابط الديناميكي عمومًا لن ينتبه إلى ld_library_path أو ما يعادله للعمليات ذات الامتيازات الجذرية. في بعض الأحيان ، إذن ، الربط الثابت ينقذ اليوم.

بدلاً من ذلك ، يتعين على عملية التثبيت تحديد موقع المكتبات ، ولكن هذا قد يجعل من الصعب على إصدارات متعددة من البرنامج التعايش على الجهاز.

يتطلب الارتباط الديناميكي وقتًا إضافيًا لنظام التشغيل للعثور على المكتبة الديناميكية وتحميله. مع الربط الثابت ، كل شيء معًا وهو حمولة طلقة واحدة في الذاكرة.

انظر أيضا DLL الجحيم. هذا هو السيناريو الذي يكون فيه DLL الذي يحمل تشغيل نظام التشغيل هو الذي جاء مع تطبيقك ، أو الإصدار الذي يتوقعه تطبيقك.

أفضل مثال على الارتباط الديناميكي هو ، عندما تعتمد المكتبة على الأجهزة المستخدمة. في العصور القديمة ، تقرر أن تكون مكتبة الرياضيات C ديناميكية ، بحيث يمكن لكل منصة استخدام جميع إمكانيات المعالج لتحسينها.

مثال أفضل قد يكون OpenGL. OpenGL هي واجهة برمجة تطبيقات يتم تنفيذها بشكل مختلف بواسطة AMD و NVIDIA. وأنت غير قادر على استخدام تطبيق NVIDIA على بطاقة AMD ، لأن الجهاز مختلف. لا يمكنك ربط OpenGL بشكل ثابت في برنامجك ، بسبب ذلك. يتم استخدام الربط الديناميكي هنا للسماح ل API بتحسين جميع المنصات.

هناك مشكلة أخرى لم تناقشها بعد وهي إصلاح الأخطاء في المكتبة.

مع الربط الثابت ، ليس عليك فقط إعادة بناء المكتبة ، ولكن سيتعين عليهم إعادة تنفيذ وإعادة تنفيذ القابل للتنفيذ. إذا تم استخدام المكتبة للتو في واحد قابل للتنفيذ ، فقد لا يكون هذا مشكلة. ولكن كلما زاد عدد الأشخاص التنفيذيين الذين يحتاجون إلى إعادة توزيعه وإعادة توزيعه ، زاد الألم.

مع الارتباط الديناميكي ، يمكنك فقط إعادة بناء المكتبة الديناميكية وإعادة توزيعها.

يمنحك الارتباط الثابت فقط exe واحد ، inorder لإجراء تغيير تحتاج إلى إعادة ترجمة برنامجك بالكامل. بينما في الارتباط الديناميكي ، تحتاج إلى إجراء تغيير فقط في DLL ، وعندما تقوم بتشغيل EXE ، سيتم التقاط التغييرات في وقت التشغيل. من الأسهل تقديم التحديثات وإصلاحات الأخطاء عن طريق الارتباط الديناميكي (على سبيل المثال: Windows).

هناك عدد كبير ومتزايد من الأنظمة حيث يمكن أن يكون للمستوى المتطرف من الارتباط الثابت تأثير إيجابي هائل على التطبيقات وأداء النظام.

أشير إلى ما يسمى غالبًا "الأنظمة المدمجة" ، والتي يستخدم الكثير منها الآن بشكل متزايد أنظمة التشغيل للأغراض العامة ، وتستخدم هذه الأنظمة في كل شيء يمكن تخيله.

مثال شائع للغاية هو الأجهزة التي تستخدم أنظمة GNU/Linux باستخدام صندوق مشغول. لقد أخذت هذا إلى أقصى الحدود Netbsd من خلال إنشاء صورة نظام I386 (32 بت) قابلة للتمهيد والتي تتضمن كل من kernel ونظام ملفات الجذر ، فإن الأخير يحتوي crunchgen) ثنائي مع روابط صلبة لجميع البرامج التي تحتويها نفسها الكل (حسناً في آخر عدد 274) من برامج نظام الميزة الكاملة القياسية (معظمها باستثناء أدوات الأدوات) ، وهو أقل من 20 ميجابايت في الحجم (وربما يتم تشغيله بشكل مريح للغاية في نظام مع 64 ميجابايت فقط من الذاكرة (حتى مع نظام ملفات الجذر غير مضغوط وذات RAM بالكامل) ، على الرغم من أنني لم أتمكن من العثور على واحدة صغيرة جدًا لاختبارها).

لقد تم ذكره في المشاركات السابقة أن وقت بدء الثنائيات المرتبطة ثابتة أسرع (ويمكن أن يكون أ كثيرا بشكل أسرع) ، ولكن هذا جزء فقط من الصورة ، خاصةً عندما يتم ربط جميع رمز الكائن بالملف نفسه ، وخاصة بشكل خاص عندما يدعم نظام التشغيل ترحيل الرمز المباشر من الملف القابل للتنفيذ. في هذا السيناريو المثالي ، يكون وقت بدء التشغيل للبرامج حرفيا لا تذكر لأن جميع صفحات التعليمات البرمجية تقريبًا ستكون بالفعل في الذاكرة وستستخدمها القشرة (و و init أي عمليات خلفية أخرى قد تكون قيد التشغيل) ، حتى لو لم يتم تشغيل البرنامج المطلوب على الإطلاق منذ التمهيد لأنه ربما يتم تحميل صفحة واحدة فقط من الذاكرة لتلبية متطلبات وقت التشغيل للبرنامج.

ومع ذلك ، لا تزال هذه القصة بأكملها. عادةً ما أقوم بإنشاء وتثبيت نظام تشغيل NetBSD لأنظمة التطوير الكاملة الخاصة بي عن طريق ربط جميع الثنائيات. على الرغم من أن هذا يتطلب مساحة هائلة من مساحة القرص (حوالي 6.6 جيجابايت إجمالي لـ x86_64 مع كل شيء ، بما في ذلك أدوات الأدوات و X11 مرتبطة بستاتيك) (خاصة إذا احتفظ المرء بتوفير جداول رمز التصحيح الكاملة لجميع البرامج ~ 2.5 جيجابايت) ، فإن النتيجة لا تزال يعمل بشكل أسرع بشكل عام ، وبالنسبة لبعض المهام ، يستخدم حتى الذاكرة أقل من نظام متصل بالديناميكي الذي يزعم مشاركة صفحات رمز المكتبة. القرص رخيص (حتى القرص السريع) ، والذاكرة لذاكرة التخزين المؤقت في كثير من الأحيان تستخدم ملفات القرص المستخدم ld.so تكلفة بدء التشغيل لكل عملية تبدأ كل سيستغرق الوقت لساعات وساعات من دورات وحدة المعالجة المركزية بعيدًا عن المهام التي تتطلب بدء العديد من العمليات ، خاصةً عند استخدام نفس البرامج مرارًا وتكرارًا ، مثل المجمعين على نظام التطوير. يمكن أن تقلل برامج أدوات الأدوات المرتبطة بالستاتيك أوقات بناء بنية متعددة البنية بأكملها لأنظامي ساعات. لا يزال يتعين علي بناء مخطط الأدوات في أغنية الأغنية الخاصة بي crunchgen"إد ثنائي ، لكني أظن أنه عندما أفعل سيكون هناك المزيد من ساعات البناء المحفوظة بسبب الفوز في ذاكرة التخزين المؤقت لوحدة المعالجة المركزية.

يتضمن الارتباط الثابت الملفات التي يحتاجها البرنامج في ملف قابل للتنفيذ واحد.

الارتباط الديناميكي هو ما ستعتبره المعتاد ، مما يجعل القابل للتنفيذ لا يزال يتطلب DLLs وأن تكون في نفس الدليل (أو يمكن أن تكون DLLs في مجلد النظام).

(DLL = رابط ديناميكي مكتبة)

يتم تجميع المواد التنفيذية المرتبطة ديناميكيًا بشكل أسرع وليست ثقيلة للموارد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top