หมายเหตุ: ฉันจะสมมติว่าเครื่องของคุณมีหน่วยความจำจับคู่หน่วย (MMU) มีรุ่น Linux (µClinux) ที่ไม่ต้องการ MMU และคำตอบนี้ไม่มีผล
MMU คืออะไร เป็นฮาร์ดแวร์ -ส่วนหนึ่งของโปรเซสเซอร์และ / หรือตัวควบคุมหน่วยความจำ การทำความเข้าใจกับการเชื่อมโยงไลบรารี่แบบแชร์ไม่ต้องการให้คุณเข้าใจอย่างแน่ชัดว่า MMU ทำงานอย่างไร แต่ MMU นั้นอนุญาตให้มีความแตกต่างระหว่างที่อยู่หน่วยความจำโลจิคัล (ที่ใช้โดยโปรแกรม) และฟิสิคัลที่อยู่หน่วยความจำ (ที่อยู่จริงบนบัสหน่วยความจำ) หน่วยความจำถูกแบ่งออกเป็นหน้าต่างๆโดยทั่วไปจะมีขนาด 4K บน Linux ด้วยเพจขนาด 4k โลจิคัลแอดเดรส 0–4095 คือเพจ 0 โลจิคัลแอดเดรส 4096–8191 คือเพจ 1 เป็นต้น MMU แม็พกับเพจฟิสิคัลของ RAM และเพจโลจิคัลปกติสามารถแม็พกับเพจฟิสิคัล 0 หรือ 1 ฟิสิคัลเพจที่กำหนดสามารถตรงกับเพจโลจิคัลหลายเพจ (นี่คือวิธีการแบ่งใช้หน่วยความจำ: เพจโลจิคัลหลายเพจสอดคล้องกับเพจฟิสิคัลเดียวกัน) หมายเหตุสิ่งนี้ใช้โดยไม่คำนึงถึง OS; มันเป็นคำอธิบายของฮาร์ดแวร์
ในการสลับกระบวนการเคอร์เนลเปลี่ยนการแมปเพจ MMU เพื่อให้แต่ละกระบวนการมีพื้นที่ของตนเอง ที่อยู่ 4096 ในกระบวนการ 1000 สามารถ (และมักจะ) แตกต่างอย่างสิ้นเชิงจากที่อยู่ 4096 ในกระบวนการ 1001
สวยมากเมื่อใดก็ตามที่คุณเห็นที่อยู่มันเป็นที่อยู่ตรรกะ โปรแกรมพื้นที่ผู้ใช้แทบจะไม่เคยจัดการกับที่อยู่ทางกายภาพ
ตอนนี้มีหลายวิธีในการสร้างห้องสมุดเช่นกัน สมมติว่าโปรแกรมเรียกใช้ฟังก์ชันfoo()
ในไลบรารี ซีพียูไม่ทราบอะไรเกี่ยวกับสัญลักษณ์หรือการเรียกใช้ฟังก์ชั่นจริง ๆ เพียงรู้วิธีที่จะข้ามไปยังที่อยู่แบบลอจิคัลและรันโค้ดใด ๆ ที่พบที่นั่น มีสองวิธีในการทำสิ่งนี้ (และสิ่งที่คล้ายกันจะมีผลเมื่อห้องสมุดเข้าถึงข้อมูลทั่วโลกของตัวเองและอื่น ๆ ):
- มันอาจยากรหัสที่อยู่ตรรกะบางอย่างที่จะเรียกมันได้ที่ นี้ต้องการให้ห้องสมุดเสมอสามารถโหลดได้ตามที่อยู่ตรรกะเดียวกันแน่นอน หากสองไลบรารีต้องการที่อยู่เดียวกันการเชื่อมโยงแบบไดนามิกล้มเหลวและคุณไม่สามารถเปิดโปรแกรมได้ ไลบรารีอาจต้องการไลบรารีอื่นดังนั้นโดยทั่วไปจำเป็นต้องมีไลบรารีทั้งหมดบนระบบเพื่อให้มีที่อยู่แบบลอจิคัลที่ไม่ซ้ำกัน มันเร็วมาก แต่ถ้ามันใช้งานได้ (นี่คือสิ่งที่ a.out ทำในสิ่งต่างๆและประเภทของการตั้งค่าที่ prelinking ทำเช่นนั้น)
- มันสามารถเขียนโค้ดที่อยู่ลอจิคัลปลอมได้ยากและบอกให้ linker แบบไดนามิกแก้ไขในอันที่ถูกต้องเมื่อทำการโหลดไลบรารี ค่าใช้จ่ายนี้ค่อนข้างสมเหตุสมผลเมื่อโหลดไลบรารี แต่หลังจากนั้นจะรวดเร็วมาก
- มันสามารถเพิ่มเลเยอร์ทางอ้อม: ใช้CPU registerเพื่อเก็บโลจิคัลแอดเดรสที่โหลดไลบรารีไว้จากนั้นเข้าถึงทุกอย่างเป็นออฟเซ็ตจากรีจิสเตอร์นั้น สิ่งนี้จะกำหนดค่าประสิทธิภาพสำหรับการเข้าถึงแต่ละครั้ง
ค่อนข้างมากไม่มีใครใช้อันดับ 1 อีกต่อไปอย่างน้อยก็ไม่ใช่ในระบบที่ใช้งานทั่วไป การเก็บรายการที่อยู่แบบลอจิคัลที่ไม่ซ้ำกันนั้นเป็นไปไม่ได้ในระบบ 32 บิต (มีไม่เพียงพอที่จะไปไหน) และฝันร้ายด้านการดูแลระบบ 64- บิต การเรียงลำดับการลิงก์ล่วงหน้าของสิ่งนี้ทำได้บนพื้นฐานต่อระบบ
การใช้ # 2 หรือ # 3 นั้นขึ้นอยู่กับว่าห้องสมุดนั้นสร้างขึ้นด้วย-fPIC
ตัวเลือก (รหัสอิสระของ GCC ) หรือไม่ # 2 ไม่ใช้ # 3 อยู่ด้วย โดยทั่วไปแล้วไลบรารีจะถูกสร้างขึ้นด้วย-fPIC
ดังนั้น # 3 จึงเป็นสิ่งที่เกิดขึ้น
สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ Ulrich Drepper ของวิธีการเขียนห้องสมุดที่ใช้ร่วมกัน (PDF)
ดังนั้นในที่สุดคำถามของคุณสามารถตอบได้:
- หากห้องสมุดสร้างขึ้นด้วย
-fPIC
(อย่างที่ควรจะเป็น) เกือบทุกหน้าจะเหมือนกันทุกขั้นตอนที่โหลด กระบวนการของคุณa
และb
อาจโหลดไลบรารีด้วยที่อยู่แบบโลจิคัลที่แตกต่างกัน แต่สิ่งเหล่านั้นจะชี้ไปยังหน้าฟิสิคัลเดียวกัน: หน่วยความจำจะถูกแชร์ นอกจากนี้ข้อมูลใน RAM ตรงกับสิ่งที่อยู่ในดิสก์ดังนั้นจึงสามารถโหลดได้เมื่อจำเป็นโดยตัวจัดการข้อบกพร่องของหน้าเท่านั้น
- หากห้องสมุดถูกสร้างโดยไม่ต้อง
-fPIC
ปรากฎว่าหน้าส่วนใหญ่ของห้องสมุดจะต้องแก้ไขลิงค์และจะแตกต่าง ดังนั้นพวกเขาจะต้องแยกหน้าทางกายภาพ (เนื่องจากมีข้อมูลที่แตกต่างกัน) นั่นหมายความว่าพวกเขาไม่ได้แชร์ หน้าไม่ตรงกับสิ่งที่อยู่บนดิสก์ดังนั้นฉันจะไม่แปลกใจถ้าโหลดไลบรารีทั้งหมด แน่นอนว่าสามารถสลับไปยังดิสก์ได้ในภายหลัง (ใน swapfile)
คุณสามารถตรวจสอบนี้ด้วยเครื่องมือหรือโดยตรงโดยการตรวจสอบไฟล์ต่างๆในpmap
/proc
ตัวอย่างเช่นนี่คือเอาต์พุต (บางส่วน) ของs ที่pmap -x
เพิ่งวางใหม่สองbc
อัน โปรดทราบว่าที่อยู่ที่แสดงโดย pmap เป็นที่อยู่แบบลอจิคัลปกติ:
pmap -x 14739
Address Kbytes RSS Dirty Mode Mapping
00007f81803ac000 244 176 0 r-x-- libreadline.so.6.2
00007f81803e9000 2048 0 0 ----- libreadline.so.6.2
00007f81805e9000 8 8 8 r---- libreadline.so.6.2
00007f81805eb000 24 24 24 rw--- libreadline.so.6.2
pmap -x 17739
Address Kbytes RSS Dirty Mode Mapping
00007f784dc77000 244 176 0 r-x-- libreadline.so.6.2
00007f784dcb4000 2048 0 0 ----- libreadline.so.6.2
00007f784deb4000 8 8 8 r---- libreadline.so.6.2
00007f784deb6000 24 24 24 rw--- libreadline.so.6.2
คุณจะเห็นว่ามีการโหลดห้องสมุดหลายส่วนและpmap -x
ให้รายละเอียดแยกกัน คุณจะสังเกตเห็นว่าที่อยู่แบบลอจิคัลนั้นแตกต่างกันระหว่างสองกระบวนการ คุณต้องการพอสมควรคาดว่าพวกเขาจะเป็นเหมือนกัน (ตั้งแต่เดียวกันโปรแกรมทำงานและคอมพิวเตอร์มักจะคาดเดาได้เช่นนั้น) แต่มีคุณลักษณะด้านความปลอดภัยที่เรียกว่าอยู่ randomization เค้าโครงพื้นที่ที่จงใจ randomizes พวกเขา
คุณสามารถเห็นได้จากความแตกต่างในขนาด (Kbytes) และขนาดที่อยู่อาศัย (RSS) ที่ส่วนไลบรารีทั้งหมดยังไม่ได้โหลด สุดท้ายคุณจะเห็นว่าสำหรับการแมปขนาดใหญ่สกปรกคือ 0 ซึ่งหมายความว่ามันสอดคล้องกับสิ่งที่อยู่บนดิสก์
คุณสามารถ re-run ด้วยpmap -XX
และมันจะแสดงให้คุณขึ้นอยู่กับรุ่นเคอร์เนลที่คุณกำลังทำงานอยู่ -XX การส่งออกจะแตกต่างกันโดย kernel รุ่นว่าการทำแผนที่แรกมีShared_Clean
176 RSS
ซึ่งตรงตรงกับ Shared
หน่วยความจำหมายความว่าหน้าฟิสิคัลจะถูกแชร์ระหว่างหลายกระบวนการและเนื่องจากตรงกับ RSS นั่นหมายความว่าไลบรารีทั้งหมดที่อยู่ในหน่วยความจำนั้นถูกแชร์ (ดูที่ดูเพิ่มเติมด้านล่างเพื่อดูคำอธิบายเพิ่มเติมเกี่ยวกับการแชร์และส่วนตัว)
pmap -XX 17739
Address Perm Offset Device Inode Size Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked VmFlagsMapping
7f784dc77000 r-xp 00000000 fd:00 1837043 244 176 19 176 0 0 0 176 0 0 0 4 4 0 rd ex mr mw me sd libreadline.so.6.2
7f784dcb4000 ---p 0003d000 fd:00 1837043 2048 0 0 0 0 0 0 0 0 0 0 4 4 0 mr mw me sd libreadline.so.6.2
7f784deb4000 r--p 0003d000 fd:00 1837043 8 8 8 0 0 0 8 8 8 0 0 4 4 0 rd mr mw me ac sd libreadline.so.6.2
7f784deb6000 rw-p 0003f000 fd:00 1837043 24 24 24 0 0 0 24 24 24 0 0 4 4 0 rd wr mr mw me ac sd libreadline.so.6.2
ดูสิ่งนี้ด้วย
-fPIC
ใช้งานมีการเปลี่ยนแปลงอย่างสมบูรณ์เมื่อไม่นานมานี้)?