การโหลดไลบรารีที่แบ่งใช้และการใช้ RAM


40

ฉันสงสัยเกี่ยวกับวิธีที่ Linux จัดการไลบรารีที่แชร์ (อันที่จริงฉันกำลังพูดถึง Maemo Fremantle, ดิสทริบิวเตอร์เดเบียนที่เปิดตัวในปี 2009 ทำงานบน RAM ขนาด 256MB)

สมมติว่าเรามีไฟล์ประมวลผลสองไฟล์เชื่อมโยงไปยัง libQtCore.so.4 และใช้สัญลักษณ์ (โดยใช้คลาสและฟังก์ชัน) เพื่อประโยชน์ของความเรียบง่ายขอเรียกพวกเขาและa bเราสันนิษฐานว่าลิงก์ประมวลผลทั้งสองเชื่อมโยงไปยังไลบรารีเดียวกัน

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

bจากนั้นเราก็เปิด เราคิดว่าaยังคงทำงานอยู่ bเชื่อมโยงไปยัง libQtCore.so.4 เกินไปและใช้บางส่วนของการเรียนที่aใช้ aแต่ยังมีบางส่วนที่ไม่ได้ใช้งานโดย ห้องสมุดจะถูกโหลดสองครั้ง (แยกกันaและแยกต่างหากb) หรือพวกเขาจะใช้วัตถุเดียวกันอยู่แล้วใน RAM หากbไม่มีสัญลักษณ์ใหม่และaกำลังใช้งาน RAM ที่ใช้งานโดยไลบรารีที่แชร์เพิ่มขึ้นหรือไม่ (หรือความแตกต่างจะไม่มีนัยสำคัญ)

คำตอบ:


53

หมายเหตุ: ฉันจะสมมติว่าเครื่องของคุณมีหน่วยความจำจับคู่หน่วย (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()ในไลบรารี ซีพียูไม่ทราบอะไรเกี่ยวกับสัญลักษณ์หรือการเรียกใช้ฟังก์ชั่นจริง ๆ เพียงรู้วิธีที่จะข้ามไปยังที่อยู่แบบลอจิคัลและรันโค้ดใด ๆ ที่พบที่นั่น มีสองวิธีในการทำสิ่งนี้ (และสิ่งที่คล้ายกันจะมีผลเมื่อห้องสมุดเข้าถึงข้อมูลทั่วโลกของตัวเองและอื่น ๆ ):

  1. มันอาจยากรหัสที่อยู่ตรรกะบางอย่างที่จะเรียกมันได้ที่ นี้ต้องการให้ห้องสมุดเสมอสามารถโหลดได้ตามที่อยู่ตรรกะเดียวกันแน่นอน หากสองไลบรารีต้องการที่อยู่เดียวกันการเชื่อมโยงแบบไดนามิกล้มเหลวและคุณไม่สามารถเปิดโปรแกรมได้ ไลบรารีอาจต้องการไลบรารีอื่นดังนั้นโดยทั่วไปจำเป็นต้องมีไลบรารีทั้งหมดบนระบบเพื่อให้มีที่อยู่แบบลอจิคัลที่ไม่ซ้ำกัน มันเร็วมาก แต่ถ้ามันใช้งานได้ (นี่คือสิ่งที่ a.out ทำในสิ่งต่างๆและประเภทของการตั้งค่าที่ prelinking ทำเช่นนั้น)
  2. มันสามารถเขียนโค้ดที่อยู่ลอจิคัลปลอมได้ยากและบอกให้ linker แบบไดนามิกแก้ไขในอันที่ถูกต้องเมื่อทำการโหลดไลบรารี ค่าใช้จ่ายนี้ค่อนข้างสมเหตุสมผลเมื่อโหลดไลบรารี แต่หลังจากนั้นจะรวดเร็วมาก
  3. มันสามารถเพิ่มเลเยอร์ทางอ้อม: ใช้CPU registerเพื่อเก็บโลจิคัลแอดเดรสที่โหลดไลบรารีไว้จากนั้นเข้าถึงทุกอย่างเป็นออฟเซ็ตจากรีจิสเตอร์นั้น สิ่งนี้จะกำหนดค่าประสิทธิภาพสำหรับการเข้าถึงแต่ละครั้ง

ค่อนข้างมากไม่มีใครใช้อันดับ 1 อีกต่อไปอย่างน้อยก็ไม่ใช่ในระบบที่ใช้งานทั่วไป การเก็บรายการที่อยู่แบบลอจิคัลที่ไม่ซ้ำกันนั้นเป็นไปไม่ได้ในระบบ 32 บิต (มีไม่เพียงพอที่จะไปไหน) และฝันร้ายด้านการดูแลระบบ 64- บิต การเรียงลำดับการลิงก์ล่วงหน้าของสิ่งนี้ทำได้บนพื้นฐานต่อระบบ

การใช้ # 2 หรือ # 3 นั้นขึ้นอยู่กับว่าห้องสมุดนั้นสร้างขึ้นด้วย-fPICตัวเลือก (รหัสอิสระของ GCC ) หรือไม่ # 2 ไม่ใช้ # 3 อยู่ด้วย โดยทั่วไปแล้วไลบรารีจะถูกสร้างขึ้นด้วย-fPICดังนั้น # 3 จึงเป็นสิ่งที่เกิดขึ้น

สำหรับรายละเอียดเพิ่มเติมโปรดดูที่ Ulrich Drepper ของวิธีการเขียนห้องสมุดที่ใช้ร่วมกัน (PDF)

ดังนั้นในที่สุดคำถามของคุณสามารถตอบได้:

  1. หากห้องสมุดสร้างขึ้นด้วย -fPIC (อย่างที่ควรจะเป็น) เกือบทุกหน้าจะเหมือนกันทุกขั้นตอนที่โหลด กระบวนการของคุณaและbอาจโหลดไลบรารีด้วยที่อยู่แบบโลจิคัลที่แตกต่างกัน แต่สิ่งเหล่านั้นจะชี้ไปยังหน้าฟิสิคัลเดียวกัน: หน่วยความจำจะถูกแชร์ นอกจากนี้ข้อมูลใน RAM ตรงกับสิ่งที่อยู่ในดิสก์ดังนั้นจึงสามารถโหลดได้เมื่อจำเป็นโดยตัวจัดการข้อบกพร่องของหน้าเท่านั้น
  2. หากห้องสมุดถูกสร้างโดยไม่ต้อง -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_Clean176 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ใช้งานมีการเปลี่ยนแปลงอย่างสมบูรณ์เมื่อไม่นานมานี้)?
Hauke ​​Laging

@crisron ขอบคุณสำหรับการแก้ไข FYI, Markdown จะนับให้คุณ - ผลลัพธ์ที่แสดงซ้ำของฉัน1. ถูกต้อง นอกจากนี้ฉันทำการเปลี่ยนแปลงบางอย่างกับสิ่งที่คุณทำ - "ที่อยู่เริ่มต้น" เป็นศัพท์แสงทางเทคนิคฉันอาจทำให้เกิดความสับสนโดยใส่ "ตรรกะ" ไว้ตรงกลาง ฉันเปลี่ยนมันเพื่อกำจัดศัพท์แสง นอกจากนี้หน้าเว็บจะเทียบเท่ากับที่อยู่เหล่านั้น AFAIK เป็นไปไม่ได้ที่ที่อยู่เหล่านั้นจะเป็นหน้าอื่น ฉันลองอีกครั้งเปลี่ยนคำสั่งหวังว่าชัดเจน
Derobert

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