การเชื่อมโยงแบบคงที่เทียบกับการเชื่อมโยงแบบไดนามิก


399

มีเหตุผลด้านประสิทธิภาพที่น่าสนใจในการเลือกการเชื่อมโยงแบบคงที่มากกว่าการเชื่อมโยงแบบไดนามิกหรือในทางกลับกันในบางสถานการณ์? ฉันได้ยินหรืออ่านข้อความต่อไปนี้ แต่ฉันไม่รู้เรื่องเพียงพอที่จะรับรองความจริง

1) ความแตกต่างของประสิทธิภาพรันไทม์ระหว่างการลิงก์แบบสแตติกและการลิงก์แบบไดนามิกนั้นมักจะเล็กน้อย

2) (1) ไม่เป็นความจริงหากใช้คอมไพเลอร์การทำโปรไฟล์ที่ใช้ข้อมูลโปรไฟล์เพื่อออพติคอลฮอตพา ธ ของโปรแกรมเนื่องจากการเชื่อมโยงแบบสแตติกคอมไพเลอร์สามารถปรับทั้งโค้ดของคุณและรหัสไลบรารี ด้วยการเชื่อมโยงแบบไดนามิกรหัสของคุณเท่านั้นที่สามารถเพิ่มประสิทธิภาพ หากใช้เวลาส่วนใหญ่ในการเรียกใช้รหัสห้องสมุดอาจทำให้เกิดความแตกต่างอย่างมาก มิฉะนั้น (1) ยังคงใช้


59
"ด้วยการเชื่อมโยงแบบคงที่ผู้รวบรวมสามารถปรับ .. รหัสห้องสมุด" แต่ถ้ามันรวบรวมที่! หากคุณเพียงลิงก์ไปยังไฟล์วัตถุที่รวบรวมไว้ล่วงหน้าคอมไพเลอร์ของคุณจะไม่ได้รับโอกาสเพิ่มประสิทธิภาพ

3
ถ้านั่นเป็นเรื่องจริงแสดงว่าคุณพูดถูก แต่ก็มีคำถามบางอย่างเกี่ยวกับความจริงที่ว่ามันเป็นอย่างไรกับคอมไพเลอร์สมัยใหม่หากมีใครสามารถยืนยันวิธีนี้ไม่ทางใดก็ทางหนึ่ง
Eloff

5
ด้วยคอมไพเลอร์คอมไพล์รหัสพื้นเมือง (เช่นคอมไพเลอร์ C / C ++ ส่วนใหญ่) ไม่มีโอกาสเพิ่มเติมสำหรับการปรับโค้ดให้เหมาะสม หากโค้ดถูกคอมไพล์เป็นภาษากลางบางภาษา (เช่น. Net IL) คอมไพเลอร์ JIT จะถูกเรียกใช้เมื่อไลบรารีได้รับการโหลดเพื่อรวบรวมเพื่อเป็นรหัสเนทีฟ การรวบรวมครั้งสุดท้ายนั้นจะดีขึ้นเรื่อย ๆ เมื่อเวลาผ่านไปเมื่อคอมไพเลอร์ JIT วิวัฒนาการ
Tarydon

3
@Eloff: VS2008 ทำสิ่งนั้นอย่างแน่นอนด้วยการเปิดใช้งาน LTCG (ไฟล์ lib กลายเป็นเรื่องใหญ่ แต่ .. ) ฉันเล่นกับมันแล้วและสำหรับคนที่สนใจใน "คอมไพเลอร์ของฉันจะทำอะไรให้ฉันได้บ้าง" มันไม่มีอะไรน่าพิศวงเลย
peterchen

คำตอบ:


348
  • การเชื่อมโยงแบบไดนามิกสามารถลดปริมาณการใช้ทรัพยากรทั้งหมด (ถ้ามีมากกว่าหนึ่งกระบวนการใช้ไลบรารีเดียวกัน (รวมถึงรุ่นใน "เดียวกัน" แน่นอน)) ฉันเชื่อว่านี่เป็นข้อโต้แย้งที่ผลักดันให้มีอยู่ในสภาพแวดล้อมส่วนใหญ่ ที่นี่ "ทรัพยากร" รวมถึงพื้นที่ดิสก์ RAM และพื้นที่แคช แน่นอนถ้าลิงเกอร์แบบไดนามิกของคุณมีความยืดหยุ่นเพียงพอมีความเสี่ยงของการDLL นรก
  • การเชื่อมโยงแบบไดนามิกหมายความว่าการแก้ไขข้อบกพร่องและการอัพเกรดเป็นห้องสมุดเผยแพร่เพื่อปรับปรุงผลิตภัณฑ์ของคุณโดยไม่ต้องให้คุณจัดส่งอะไร
  • ปลั๊กอินจะเรียกลิงก์แบบไดนามิกเสมอ
  • การเชื่อมโยงแบบสแตติกหมายความว่าคุณสามารถรู้รหัสที่จะทำงานในสภาพแวดล้อมที่ จำกัดมาก(ในช่วงต้นของกระบวนการบูตหรือในโหมดช่วยเหลือ)
  • การเชื่อมโยงแบบคงที่สามารถทำให้ไบนารีง่ายต่อการกระจายไปยังสภาพแวดล้อมผู้ใช้ที่หลากหลาย (ค่าใช้จ่ายในการส่งโปรแกรมหิวทรัพยากรขนาดใหญ่และมากขึ้น)
  • การลิงก์แบบสแตติกอาจทำให้เวลาเริ่มต้นทำงานเร็วขึ้นเล็กน้อยแต่ขึ้นอยู่กับขนาดและความซับซ้อนของโปรแกรมและรายละเอียดของกลยุทธ์การโหลดระบบปฏิบัติการ

การแก้ไขบางอย่างรวมถึงคำแนะนำที่เกี่ยวข้องมากในความคิดเห็นและคำตอบอื่น ๆ ฉันต้องการทราบว่าวิธีที่คุณใช้ในเรื่องนี้ขึ้นอยู่กับสภาพแวดล้อมที่คุณวางแผนจะใช้งานระบบฝังตัวที่น้อยที่สุดอาจไม่มีทรัพยากรเพียงพอที่จะรองรับการเชื่อมโยงแบบไดนามิก ระบบขนาดเล็กที่มีขนาดใหญ่ขึ้นเล็กน้อยอาจรองรับการเชื่อมโยงแบบไดนามิกได้ดีเนื่องจากหน่วยความจำของพวกเขามีขนาดเล็กพอที่จะทำให้การประหยัด RAM จากการเชื่อมโยงแบบไดนามิกน่าสนใจมาก พีซีสำหรับผู้บริโภคที่มีปัญหาเต็มไปหมดเช่น Mark notes ทรัพยากรมหาศาลและคุณอาจปล่อยให้ปัญหาด้านความสะดวกสบายขับเคลื่อนความคิดของคุณในเรื่องนี้


ที่อยู่ที่ประสิทธิภาพและประสิทธิผลปัญหา: มันขึ้นอยู่กับ

คลาสสิกไลบรารีแบบไดนามิกต้องการเลเยอร์กาวบางชนิดซึ่งมักจะหมายถึงการจัดส่งแบบคู่หรือเลเยอร์ทางอ้อมเพิ่มเติมในการกำหนดฟังก์ชันและอาจมีค่าใช้จ่ายความเร็วเล็กน้อย (แต่เป็นเวลาการเรียกใช้ฟังก์ชัน

อย่างไรก็ตามหากคุณกำลังเรียกใช้หลายกระบวนการที่ทุกคนเรียกใช้ไลบรารีเดียวกันจำนวนมากคุณสามารถจบการบันทึกบรรทัดแคช (และชนะการทำงาน) เมื่อใช้การเชื่อมโยงแบบไดนามิกที่เกี่ยวข้องกับการใช้การเชื่อมโยงแบบคงที่ (เว้นแต่ว่าระบบปฏิบัติการสมัยใหม่นั้นฉลาดพอที่จะสังเกตเห็นเซ็กเมนต์ที่เหมือนกันในไบนารีที่เชื่อมโยงแบบคงที่ดูเหมือนว่ายากใครจะรู้?)

ปัญหาอื่น: เวลาโหลด คุณจ่ายค่าใช้จ่ายในการโหลดในบางจุด เมื่อคุณชำระค่าใช้จ่ายนี้ขึ้นอยู่กับการทำงานของระบบปฏิบัติการและการเชื่อมโยงที่คุณใช้ บางทีคุณอาจจะยอมจ่ายเงินจนกว่าคุณจะรู้ว่าคุณต้องการมัน

โปรดทราบว่าการลิงก์แบบคงที่เทียบกับแบบไดนามิกไม่ใช่ปัญหาการเพิ่มประสิทธิภาพเนื่องจากพวกเขาทั้งสองเกี่ยวข้องกับการรวบรวมแยกเป็นไฟล์วัตถุ อย่างไรก็ตามสิ่งนี้ไม่จำเป็นต้องใช้: คอมไพเลอร์สามารถใช้หลักการ "คอมไพล์" "สแตติกไลบรารี" ในรูปแบบ AST ที่ถูกย่อในขั้นต้นและ "ลิงก์" โดยการเพิ่ม AST เหล่านั้นไปยังโค้ดที่สร้างขึ้นสำหรับรหัสหลัก ไม่มีระบบใดที่ฉันใช้ทำสิ่งนี้ดังนั้นฉันจึงไม่สามารถแสดงความคิดเห็นได้ว่ามันใช้งานได้ดีเพียงใด

วิธีการตอบคำถามด้านประสิทธิภาพมักเกิดจากการทดสอบ (และใช้สภาพแวดล้อมการทดสอบให้มากที่สุดเท่าที่จะเป็นไปได้)


24
การใช้ทรัพยากรนั้นเป็นพื้นที่โค้ดซึ่งเมื่อเวลาผ่านไปมีความกังวลน้อยลง หากมีการแชร์ไลบรารี 500K ระหว่าง 5 กระบวนการนั่นคือประหยัด 2MB ซึ่งน้อยกว่า. 1% ของ RAM 3GB
Mark Ransom

3
หากไลบรารียังแชร์การแมปเสมือนเดียวกัน (ที่อยู่จริงและที่อยู่เสมือนเดียวกันในทุกกระบวนการ) ลิงก์แบบไดนามิกจะไม่บันทึกสล็อต TLB ใน MMU ของโปรเซสเซอร์ด้วยหรือไม่
Zan Lynx

6
นอกจากนี้ลิงค์แบบไดนามิกทำให้ง่ายต่อการอัปเดตรหัสห้องสมุด buggy ด้วยรุ่นที่ดีกว่า
Zan Lynx

89
@Zan นอกจากนี้ยังช่วยเพิ่มรหัส buggy ให้เป็นรุ่นที่ใช้งานได้ง่าย

6
"ปลั๊กอินจะเรียกลิงก์แบบไดนามิกเสมอ" นั่นไม่ถูกต้อง ปลั๊กอินบางรุ่นเช่น AudioUnits ของ Apple สามารถเรียกใช้ปลั๊กอินในกระบวนการแยกต่างหากและใช้ IPC นี่เป็นทางเลือกที่ปลอดภัยกว่าสำหรับการลิงก์แบบไดนามิกสำหรับปลั๊กอิน (ปลั๊กอินไม่สามารถโฮสต์ล้มเหลว) แนะนำให้อัปเดตคำตอบเป็น "ปลั๊กอินอาจต้องมีการเชื่อมโยงแบบไดนามิก" หรือคล้ายกัน
เทย์เลอร์

68

1) ขึ้นอยู่กับความจริงที่ว่าการเรียกใช้ฟังก์ชัน DLL มักจะใช้การกระโดดทางอ้อมเป็นพิเศษเสมอ วันนี้มันมักจะเล็กน้อย ภายใน DLL มีค่าใช้จ่ายเพิ่มเติมในซีพียู i386 เพราะพวกเขาไม่สามารถสร้างรหัสอิสระของตำแหน่งได้ ใน amd64 การกระโดดสามารถสัมพันธ์กับตัวนับโปรแกรมดังนั้นนี่เป็นการปรับปรุงที่ยิ่งใหญ่

2) สิ่งนี้ถูกต้อง ด้วยการปรับให้เหมาะสมที่ได้รับคำแนะนำจากการทำโปรไฟล์คุณจะสามารถชนะประสิทธิภาพได้ประมาณ 10-15 เปอร์เซ็นต์ ตอนนี้ความเร็วของ CPU ถึงขีด จำกัด แล้วมันน่าจะคุ้มค่าแล้ว

ฉันจะเพิ่ม: (3) ตัวเชื่อมโยงสามารถจัดเรียงฟังก์ชั่นในการจัดกลุ่มแคชที่มีประสิทธิภาพมากขึ้น นอกจากนี้ยังอาจมีผลต่อเวลาเริ่มต้นของแอปพลิเคชันโดยเฉพาะอย่างยิ่ง (ขึ้นอยู่กับผลลัพธ์ที่ฉันได้เห็นด้วยคอมไพเลอร์ Sun C ++)

และอย่าลืมว่าด้วย DLLs จะไม่มีการกำจัดโค้ดที่ตายแล้ว รหัส DLL อาจไม่เหมาะสมที่สุดทั้งนี้ขึ้นอยู่กับภาษา ฟังก์ชั่นเสมือนเป็นเสมือนจริงเสมอเพราะคอมไพเลอร์ไม่รู้ว่าลูกค้าเขียนทับมันหรือไม่

ด้วยเหตุผลเหล่านี้ในกรณีที่ไม่มีความต้องการที่แท้จริงสำหรับ DLLs ให้ใช้การรวบรวมแบบคงที่

แก้ไข (เพื่อตอบความคิดเห็นโดยผู้ใช้ขีดล่าง)

นี่คือแหล่งข้อมูลที่ดีเกี่ยวกับปัญหาตำแหน่งรหัสอิสระhttp://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries/

ตามที่อธิบายไว้ x86 ไม่ได้มี AFAIK สำหรับสิ่งอื่นแล้วช่วงการกระโดด 15 บิตและไม่ใช่การกระโดดและการโทรแบบไม่มีเงื่อนไข นั่นเป็นเหตุผลที่ฟังก์ชั่น (จากเครื่องกำเนิดไฟฟ้า) ที่มีมากกว่า 32K เป็นปัญหาเสมอและจำเป็นต้องใช้แทรมโพลีนแบบฝัง

แต่บนระบบปฏิบัติการ x86 ยอดนิยมเช่น Linux คุณไม่จำเป็นต้องสนใจว่าไฟล์. so / DLL ไม่ได้ถูกสร้างขึ้นด้วยgccสวิตช์-fpic(ซึ่งบังคับใช้การใช้ตารางกระโดดทางอ้อม) เพราะถ้าคุณทำไม่ได้รหัสถูกแก้ไขเช่นเดียวกับ linker ปกติจะย้ายมัน แต่ในขณะที่ทำสิ่งนี้มันทำให้ส่วนของโค้ดไม่สามารถแชร์ได้และมันจะต้องทำการแมปเต็มรูปแบบของรหัสจากดิสก์ไปยังหน่วยความจำและสัมผัสทั้งหมดก่อนที่จะสามารถใช้งานได้ (ล้างแคชส่วนใหญ่ เมื่อสิ่งนี้ถูกพิจารณาว่าช้า

ดังนั้นคุณจะไม่ได้รับผลประโยชน์ใด ๆ อีกต่อไป

ผมจำไม่ได้ว่าสิ่งที่ OS (Solaris หรือ FreeBSD) ให้ฉันมีปัญหากับการสร้างระบบยูนิกซ์ของฉันเพราะฉันก็ไม่ได้ทำเช่นนี้และสงสัยว่าทำไมมันกระแทกจนกว่าฉันจะนำมาใช้ในการ-fPICgcc


4
ฉันชอบคำตอบนี้เพราะเป็นเพียงคนเดียวที่ตอบคำถามที่ฉันยกประเด็น
Eloff

มันจะน่าสนใจที่จะมีการอ้างอิงเกี่ยวกับ technicalities DLL เหล่านั้นและการเปรียบเทียบระหว่างระบบปฏิบัติการที่แตกต่างกัน
UncleZeiv

ดูเหมือนว่าจะดี แต่ความเร็วของ CPU ไม่ถึงขีด จำกัด แน่นอน
Aidiakapi

67

เชื่อมโยงแบบไดนามิกเป็นวิธีเดียวที่ปฏิบัติเพื่อตอบสนองความต้องการใบอนุญาตบางอย่างเช่นแอลจี


17
ตราบใดที่ผู้ใช้ปลายทางสามารถเชื่อมโยงกับรหัส LGPL (เช่นเนื่องจากคุณให้ซอร์สโค้ดของคุณหรือรวบรวมไฟล์ออบเจ็กต์ด้วยซอฟต์แวร์ของคุณ) การเชื่อมโยงแบบสแตติกก็ใช้ได้ นอกจากนี้หากซอฟต์แวร์ของคุณมีไว้สำหรับการใช้งานภายใน (เช่นที่จะใช้ภายในองค์กรของคุณเท่านั้นและไม่เผยแพร่) คุณสามารถลิงก์แบบสแตติกได้ สิ่งนี้จะใช้กับซอฟต์แวร์เซิร์ฟเวอร์เช่นที่เซิร์ฟเวอร์ไม่ได้ถูกแจกจ่าย
JBentley

3
ไม่เข้าใจ คุณช่วยให้ฉันเพิ่มเติมแหล่งที่มา (หรือเพิ่มเติมอย่างละเอียด) เพื่อขอบคุณสิ่งที่คุณเขียน?
Baskaya

4
@Thorn ดูแอลจีใบอนุญาตส่วน 4.d + E คุณต้องกระจายในรูปแบบที่กำหนดให้ผู้ใช้ต้องทำการเชื่อมโยงหรือแจกจ่ายไลบรารีที่ใช้ร่วมกัน (ไดนามิก)
Mark Ransom

46

ฉันเห็นด้วยกับประเด็นที่ dnmckee กล่าวถึงบวก:

  • แอปพลิเคชันที่เชื่อมโยงแบบคงที่อาจปรับใช้งานได้ง่ายขึ้นเนื่องจากมีการขึ้นต่อกันของไฟล์น้อยกว่าหรือไม่มีเลย (.dll / .so) ที่อาจทำให้เกิดปัญหาเมื่อขาดหายไปหรือติดตั้งผิดที่

6
มันน่าสังเกตว่าคอมไพเลอร์ไปจาก Google จะมีเพียงแบบคงที่รวบรวมไบนารีสำหรับส่วนใหญ่ด้วยเหตุนี้
Hut8 8

34

เหตุผลหนึ่งที่ทำให้การสร้างการเชื่อมโยงแบบคงที่คือการตรวจสอบว่าคุณมีการปิดเต็มรูปแบบสำหรับปฏิบัติการได้นั่นคือการอ้างอิงสัญลักษณ์ทั้งหมดได้รับการแก้ไขอย่างถูกต้อง

ในฐานะที่เป็นส่วนหนึ่งของระบบขนาดใหญ่ที่ถูกสร้างและทดสอบโดยใช้การรวมอย่างต่อเนื่องการทดสอบการถดถอยในเวลากลางคืนจึงรันโดยใช้เวอร์ชันที่เชื่อมโยงแบบคงที่ของไฟล์ปฏิบัติการ ในบางครั้งเราจะเห็นว่าสัญลักษณ์ไม่สามารถแก้ไขได้และลิงก์แบบคงที่จะล้มเหลวแม้ว่าการเชื่อมโยงแบบปฏิบัติการได้จะเชื่อมโยงได้สำเร็จ

สิ่งนี้มักจะเกิดขึ้นเมื่อสัญลักษณ์ที่ฝังอยู่ใน libs ที่ใช้ร่วมกันมีชื่อที่สะกดผิดและจะไม่เชื่อมโยงแบบคงที่ ตัวเชื่อมโยงแบบไดนามิกไม่ได้แก้ปัญหาสัญลักษณ์ทั้งหมดอย่างสมบูรณ์โดยไม่คำนึงถึงการใช้การประเมินผลเชิงลึกหรือความกว้างแรกดังนั้นคุณสามารถจบการทำงานด้วยการเชื่อมโยงแบบไดนามิกที่ไม่มีการปิดเต็ม


1
จุดที่ดีมากฉันพยายามทำสิ่งนี้เมื่อเร็ว ๆ นี้ด้วยรหัสที่ฉันมีในที่ทำงาน แต่รวบรวมทุกอย่างที่พิสูจน์แล้วว่าน่ารำคาญน่ารำคาญและฉันก็ยอมแพ้
UncleZeiv

21

1 / ฉันอยู่ในโครงการที่การเชื่อมโยงแบบไดนามิกกับการเชื่อมโยงแบบคงที่ถูกเปรียบเทียบและความแตกต่างไม่ได้กำหนดว่าเล็กพอที่จะเปลี่ยนเป็นการเชื่อมโยงแบบไดนามิก (ฉันไม่ได้เป็นส่วนหนึ่งของการทดสอบฉันเพิ่งรู้ข้อสรุป)

2 / การเชื่อมโยงแบบไดนามิกมักจะเกี่ยวข้องกับ PIC (รหัสอิสระของตำแหน่ง, รหัสที่ไม่จำเป็นต้องแก้ไขขึ้นอยู่กับที่อยู่ที่โหลด) ขึ้นอยู่กับสถาปัตยกรรม PIC อาจทำให้การทำงานช้าลง แต่จำเป็นเพื่อให้ได้รับประโยชน์จากการแชร์ไลบรารี่ที่เชื่อมโยงแบบไดนามิกระหว่างสองเอ็กซีคิวต์ (และแม้แต่สองกระบวนการของเอ็กซีคิวต์เดียวกันหากระบบปฏิบัติการใช้การสุ่มโหลดที่อยู่ ฉันไม่แน่ใจว่าระบบปฏิบัติการทั้งหมดอนุญาตให้แยกสองแนวคิด แต่ Solaris และ Linux ทำและ ISTR ที่ HP-UX ทำได้เช่นกัน

3 / ฉันใช้โครงการอื่นที่ใช้การเชื่อมโยงแบบไดนามิกสำหรับคุณลักษณะ "easy patch" แต่ "easy patch" นี้ทำให้การกระจายตัวแก้ไขขนาดเล็กง่ายขึ้นเล็กน้อยและซับซ้อนขึ้นหนึ่งภาพเป็นฝันร้ายของการกำหนดเวอร์ชัน เรามักจะจบลงด้วยการผลักทุกอย่างและต้องติดตามปัญหาที่ไซต์ลูกค้าเพราะรุ่นที่ไม่ถูกต้องเป็นโทเค็น

ข้อสรุปของฉันคือฉันจะใช้การเชื่อมโยงแบบคงที่ยกเว้น:

  • สำหรับสิ่งต่าง ๆ เช่นปลั๊กอินซึ่งขึ้นอยู่กับการเชื่อมโยงแบบไดนามิก

  • เมื่อใช้งานร่วมกันเป็นสิ่งสำคัญ (ไลบรารีขนาดใหญ่ที่ใช้โดยกระบวนการหลายอย่างในเวลาเดียวกันเช่น C / C ++ รันไทม์, ไลบรารี GUI, ... ซึ่งมักจะได้รับการจัดการอย่างอิสระและกำหนด ABI ไว้อย่างเคร่งครัด)

หากต้องการใช้ "easy patch" ฉันขอยืนยันว่าห้องสมุดต้องได้รับการจัดการเหมือนไลบรารี่ขนาดใหญ่ด้านบน: พวกเขาจะต้องเป็นอิสระจาก ABI ที่กำหนดซึ่งต้องไม่เปลี่ยนแปลงโดยการแก้ไข


1
OS บางตัวสำหรับโปรเซสเซอร์ที่ไม่ใช่ PIC หรือแพง PIC จะเตรียมไลบรารีแบบไดนามิกที่จะโหลดที่อยู่เฉพาะในหน่วยความจำและถ้าพวกเขาสามารถทำเช่นนั้นพวกเขาก็แมปในสำเนาของห้องสมุดทุกกระบวนการที่เชื่อมโยงกับมัน ที่ช่วยลดโอเวอร์เฮดของ PIC ได้มาก อย่างน้อย OS X และ Linux ดิสทริบิวชันทำเช่นนี้ฉันไม่แน่ใจเกี่ยวกับ Windows
Andrew McGregor

ขอบคุณ Andrew ฉันไม่รู้ว่าลีนุกซ์รุ่นใดใช้ คุณมีการอ้างอิงที่ฉันสามารถติดตามหรือคำสำคัญที่ฉันสามารถค้นหาเพื่อเรียนรู้เพิ่มเติม? (FWIW ฉันได้ยินมาว่า Windows กำลังทำสิ่งนี้แตกต่างกันไป แต่ Windows นั้นอยู่ไกลเกินกว่าความสามารถของฉันสำหรับฉันที่พูดถึงมัน)
AProgrammer

ฉันคิดว่าคำหลักที่คุณกำลังค้นหาคือ "prelink" - เป็นการเตรียมห้องสมุดที่จะโหลดอย่างรวดเร็วตามที่อยู่ที่แน่นอนเพื่อให้การเริ่มต้นโปรแกรมเร็วขึ้น
Blaisorblade

20

สิ่งนี้จะกล่าวถึงรายละเอียดที่ดีเกี่ยวกับไลบรารี่ที่ใช้ร่วมกันบน linux และความหมายของประสิทธิภาพ


3
+1 สำหรับการเชื่อมโยงไปยัง DSO ของ Drepper ซึ่งทุกคนที่ทำไลบรารีบน Linux ควรอ่าน
janneb

10

บนระบบที่เหมือน Unix การเชื่อมโยงแบบไดนามิกสามารถทำให้ชีวิตยากขึ้นสำหรับ 'root' ในการใช้แอปพลิเคชันที่มีไลบรารีที่ใช้ร่วมกันติดตั้งในตำแหน่งที่อยู่นอกเส้นทาง นี่เป็นเพราะตัวเชื่อมโยงแบบไดนามิกโดยทั่วไปจะไม่ใส่ใจกับ LD_LIBRARY_PATH หรือสิ่งที่เทียบเท่าสำหรับกระบวนการที่มีสิทธิ์รูท บางครั้งการเชื่อมโยงแบบคงที่จะบันทึกวัน

อีกทางหนึ่งกระบวนการติดตั้งต้องค้นหาไลบรารี แต่อาจทำให้ซอฟต์แวร์หลายรุ่นยากที่จะอยู่ร่วมกันบนเครื่อง


1
ประเด็นเกี่ยวกับLD_LIBRARY_PATHไม่ใช่อุปสรรคสำหรับการใช้ไลบรารีที่ใช้ร่วมกันอย่างน้อยไม่ใช่ใน GNU / Linux เช่นถ้าคุณใส่ไลบรารีที่แบ่งใช้ในไดเรกทอรีที่../lib/สัมพันธ์กับไฟล์โปรแกรมจากนั้นด้วย GNU tool chain ตัวเลือก linker -rpath $ORIGIN/../libจะระบุการค้นหาห้องสมุดจากตำแหน่งที่สัมพันธ์กัน จากนั้นคุณสามารถย้ายแอปพลิเคชันไปพร้อมกับไลบรารีที่แชร์ที่เกี่ยวข้องทั้งหมดได้อย่างง่ายดาย การใช้เคล็ดลับนี้ไม่มีปัญหาในการใช้งานแอปพลิเคชั่นและไลบรารี่หลายเวอร์ชั่น (สมมติว่าพวกมันเกี่ยวข้องกันหากไม่ใช่คุณสามารถใช้ลิงก์สัญลักษณ์)
FooF

> สำหรับกระบวนการที่มีสิทธิ์รูท ฉันคิดว่าคุณกำลังพูดถึงโปรแกรม setuid ที่เรียกใช้จากผู้ใช้ที่ไม่ใช่รูท - มิฉะนั้นก็ไม่สมเหตุสมผล และไบนารี setuid ที่มีไลบรารีในสถานที่ที่ไม่ได้มาตรฐานนั้นแปลก แต่เนื่องจากรูทเท่านั้นที่สามารถติดตั้งโปรแกรมเหล่านั้นได้เขาจึงสามารถแก้ไข/etc/ld.so.confในกรณีนั้นได้
Blaisorblade

10

มันค่อนข้างง่ายจริงๆ เมื่อคุณทำการเปลี่ยนแปลงในซอร์สโค้ดคุณต้องการรอ 10 นาทีเพื่อสร้างหรือ 20 วินาทีหรือไม่? ยี่สิบวินาทีคือทั้งหมดที่ฉันสามารถทนได้ นอกเหนือจากนั้นฉันก็สามารถออกดาบหรือเริ่มคิดว่าฉันจะใช้การรวบรวมและการเชื่อมโยงที่แยกจากกันเพื่อนำมันกลับไปสู่เขตความสะดวกสบายได้อย่างไร


1
ฉันไม่ได้ทำการเปรียบเทียบความแตกต่างของความเร็วในการคอมไพล์ แต่ฉันจะเชื่อมโยงแบบไดนามิกถ้ามันเร็วกว่ามาก บูสต์ทำสิ่งที่ไม่ดีพอในการรวบรวมเวลาของฉัน
Eloff

9

ตัวอย่างที่ดีที่สุดสำหรับการเชื่อมโยงแบบไดนามิกคือเมื่อไลบรารีขึ้นอยู่กับฮาร์ดแวร์ที่ใช้ ในสมัยโบราณห้องสมุดคณิตศาสตร์ C ได้ตัดสินใจที่จะเป็นแบบไดนามิกเพื่อให้แต่ละแพลตฟอร์มสามารถใช้ความสามารถของโปรเซสเซอร์ทั้งหมดเพื่อปรับให้เหมาะสม

ตัวอย่างที่ดียิ่งขึ้นอาจเป็น OpenGL OpenGl เป็น API ที่ใช้งานแตกต่างกันโดย AMD และ NVidia และคุณไม่สามารถใช้การติดตั้ง NVidia บนการ์ด AMD ได้เนื่องจากฮาร์ดแวร์แตกต่างกัน คุณไม่สามารถลิงก์ OpenGL แบบคงที่เข้ากับโปรแกรมของคุณได้ การลิงก์แบบไดนามิกใช้ที่นี่เพื่อให้ API ได้รับการปรับให้เหมาะสมที่สุดสำหรับทุกแพลตฟอร์ม


8

การเชื่อมโยงแบบไดนามิกต้องใช้เวลาเพิ่มเติมสำหรับระบบปฏิบัติการเพื่อค้นหาไลบรารีแบบไดนามิกและโหลด ด้วยการเชื่อมโยงแบบคงที่ทุกอย่างเข้าด้วยกันและเป็นโหลดครั้งเดียวในหน่วยความจำ

ยังดูDLL นรก นี่คือสถานการณ์ที่ DLL ที่ระบบปฏิบัติการโหลดไม่ใช่ที่มาพร้อมกับแอปพลิเคชันของคุณหรือเวอร์ชันที่แอปพลิเคชันของคุณคาดหวัง


1
สิ่งสำคัญที่ควรทราบว่ามีช่วงของการตอบโต้เพื่อหลีกเลี่ยง DLL Hell
ocodo

5

ปัญหาอื่นที่ยังไม่ได้กล่าวถึงคือการแก้ไขข้อบกพร่องในห้องสมุด

ด้วยการเชื่อมโยงแบบคงที่คุณไม่เพียง แต่ต้องสร้างไลบรารีขึ้นมาใหม่ แต่จะต้องเชื่อมโยงและเผยแพร่ไฟล์ปฏิบัติการใหม่อีกครั้ง หากไลบรารีถูกใช้ในการปฏิบัติการเพียงครั้งเดียวสิ่งนี้อาจไม่เป็นปัญหา แต่ยิ่งไฟล์ปฏิบัติการที่ต้องมีการเชื่อมโยงและแจกจ่ายซ้ำมากเท่าไหร่ความเจ็บปวดก็จะยิ่งมากขึ้นเท่านั้น

ด้วยการเชื่อมโยงแบบไดนามิกคุณเพียงแค่สร้างและแจกจ่ายไลบรารีแบบไดนามิกอีกครั้งและเสร็จสิ้น


2

การเชื่อมโยงแบบสแตติกช่วยให้คุณมี exe เพียงอันเดียวเพื่อที่จะทำการเปลี่ยนแปลงที่คุณต้องการในการคอมไพล์โปรแกรมของคุณใหม่ทั้งหมด ในขณะที่การเชื่อมโยงแบบไดนามิกคุณจะต้องทำการเปลี่ยนแปลงเฉพาะกับ dll และเมื่อคุณเรียกใช้ exe การเปลี่ยนแปลงจะถูกหยิบขึ้นมาใน runtime.Its ง่ายขึ้นเพื่อให้การปรับปรุงและแก้ไขข้อผิดพลาดโดยการเชื่อมโยงแบบไดนามิก (เช่น: windows)


2

มีระบบจำนวนมากและเพิ่มขึ้นซึ่งการเชื่อมโยงคงที่ในระดับที่สูงสามารถมีผลกระทบเชิงบวกอย่างมากต่อการใช้งานและประสิทธิภาพของระบบ

ฉันอ้างถึงสิ่งที่มักเรียกว่า "ระบบฝังตัว" ซึ่งส่วนใหญ่ใช้ระบบปฏิบัติการที่ใช้งานทั่วไปมากขึ้นเรื่อย ๆ และระบบเหล่านี้ใช้สำหรับทุกสิ่งเท่าที่จะเป็นไปได้

ตัวอย่างที่พบมากเป็นอุปกรณ์ที่ใช้ GNU / ระบบ Linux ใช้Busybox ฉันได้นำสิ่งนี้ไปสุดโต่งกับNetBSDโดยการสร้างอิมเมจระบบที่สามารถบูตได้ i386 (32- บิต) ที่มีทั้งเคอร์เนลและระบบไฟล์รูทของมันซึ่งหลังนี้มีcrunchgenไบนารีแบบลิงก์คงที่ (โดย) พร้อมฮาร์ดลิงก์ โปรแกรมทั้งหมดที่ตัวเองมีทั้งหมด (ดีที่นับ 274) ของมาตรฐานระบบโปรแกรมเต็มคุณลักษณะ (ส่วนใหญ่ยกเว้น toolchain) และมันมีค่าน้อยกว่า 20 ล้านไบต์ในขนาด (และอาจจะทำงานสบายมากในระบบที่มีเพียง 64 ของหน่วยความจำ (แม้ว่าระบบไฟล์รูทจะไม่มีการบีบอัดและทั้งหมดใน RAM) แต่ฉันไม่สามารถหาตัวเล็ก ๆ ที่จะทดสอบได้)

มีการกล่าวถึงในโพสต์ก่อนหน้านี้ว่าเวลาเริ่มต้นของไบนารีที่เชื่อมโยงแบบสแตติกนั้นเร็วกว่า (และอาจเร็วกว่ามาก ) แต่นั่นเป็นเพียงส่วนหนึ่งของรูปภาพโดยเฉพาะอย่างยิ่งเมื่อรหัสวัตถุทั้งหมดเชื่อมโยงกัน ไฟล์และยิ่งโดยเฉพาะอย่างยิ่งเมื่อระบบปฏิบัติการรองรับการเพจตามความต้องการของรหัสโดยตรงจากไฟล์ปฏิบัติการ ในสถานการณ์ที่เหมาะนี้เวลาเริ่มต้นของโปรแกรมเป็นตัวอักษรเล็กน้อยตั้งแต่เกือบทุกหน้าของรหัสแล้วจะอยู่ในหน่วยความจำและถูกใช้โดยเปลือก (และและinitกระบวนการพื้นหลังอื่น ๆ ที่อาจจะมีการทำงาน) แม้ว่าโปรแกรมที่ร้องขอไม่ได้ เคยรันมาตั้งแต่เริ่มระบบเนื่องจากอาจโหลดหน้าหน่วยความจำเพียงหน้าเดียวเพื่อตอบสนองความต้องการรันไทม์ของโปรแกรม

อย่างไรก็ตามนั่นก็ยังไม่ใช่เรื่องราวทั้งหมด ฉันมักจะสร้างและใช้ระบบปฏิบัติการ NetBSD ที่ติดตั้งสำหรับระบบการพัฒนาเต็มรูปแบบของฉันโดยการเชื่อมโยงแบบคงที่ไบนารีทั้งหมด แม้ว่าสิ่งนี้จะใช้พื้นที่ดิสก์จำนวนมาก (รวมถึง ~ 6.6GB สำหรับ x86_64 กับทุกสิ่งรวมถึง toolchain และ X11 static-linked) (โดยเฉพาะหากมีการเก็บตารางสัญลักษณ์ debug เต็มรูปแบบสำหรับโปรแกรมทั้งหมดอีก ~ 2.5GB) ผลลัพธ์ยังคงอยู่ ทำงานโดยรวมได้เร็วขึ้นและสำหรับบางงานยังใช้หน่วยความจำน้อยกว่าระบบที่เชื่อมโยงแบบไดนามิกทั่วไปที่อ้างว่าแบ่งปันเพจโค้ดไลบรารี ดิสก์มีราคาถูก (แม้แต่ดิสก์ที่เร็ว) และหน่วยความจำในการแคชไฟล์ดิสก์ที่ใช้บ่อยนั้นก็ค่อนข้างถูก แต่วงจร CPU ไม่ได้จริงๆและจ่ายค่าld.soเริ่มต้นสำหรับทุกกระบวนการที่เริ่มต้นทุก ๆเวลาที่เริ่มต้นจะใช้เวลาเป็นชั่วโมงและชั่วโมงของ CPU รอบออกจากงานที่ต้องเริ่มต้นกระบวนการจำนวนมากโดยเฉพาะเมื่อมีการใช้โปรแกรมเดียวกันซ้ำไปซ้ำมาเช่นคอมไพเลอร์ในระบบการพัฒนา คงเชื่อมโยง toolchain โปรแกรมสามารถลดทั้ง OS หลายสถาปัตยกรรมการสร้างครั้งสำหรับระบบของฉันโดยชั่วโมง ฉันยังไม่ได้สร้าง toolchain ลงในcrunchgen'ed ไบนารี' ของฉันเดียวแต่ฉันสงสัยว่าเมื่อฉันทำจะมีเวลาในการสร้างมากกว่าหนึ่งชั่วโมงเนื่องจากประหยัดสำหรับแคชของ CPU


2

การลิงก์แบบสแตติกรวมถึงไฟล์ที่โปรแกรมต้องการในไฟล์เรียกทำงานไฟล์เดียว

การเชื่อมโยงแบบไดนามิกเป็นสิ่งที่คุณจะพิจารณาตามปกติมันทำให้สามารถเรียกใช้งานได้ซึ่งยังคงต้องใช้ DLL และอยู่ในไดเรกทอรีเดียวกัน (หรือ DLLs อาจอยู่ในโฟลเดอร์ระบบ)

(DLL = ไลบรารีลิงก์แบบไดนามิก )

ไฟล์ประมวลผลที่ลิงก์แบบไดนามิกนั้นรวบรวมได้เร็วกว่าและไม่หนักเหมือนทรัพยากร


0

Static linking เป็นกระบวนการในเวลารวบรวมเมื่อเนื้อหาที่เชื่อมโยงถูกคัดลอกลงในไบนารีหลักและกลายเป็นไบนารีเดียว

จุดด้อย:

  • เวลารวบรวมนานกว่า
  • เอาต์พุตไบนารีใหญ่กว่า

Dynamic linkingเป็นกระบวนการในรันไทม์เมื่อโหลดเนื้อหาที่เชื่อมโยง เทคนิคนี้ช่วยให้:

  • อัพเกรดไบนารีที่เชื่อมโยงโดยไม่ต้องคอมไพล์หลักใหม่ที่เพิ่มABIความเสถียร[เกี่ยวกับ]
  • มีสำเนาที่แชร์เดียว

จุดด้อย:

  • เวลาเริ่มช้าลง (ควรคัดลอกเนื้อหาที่เชื่อมโยง)
  • ข้อผิดพลาดตัวเชื่อมโยงถูกส่งออกไปในรันไทม์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.