อ็อบเจ็กต์/DLL ที่ใช้ร่วมกันถูกโหลดโดยกระบวนการที่แตกต่างกันลงในพื้นที่หน่วยความจำที่แตกต่างกันหรือไม่

ฉันกำลังพยายามหาวิธีที่ระบบปฏิบัติการจัดการกับกระบวนการที่ไม่เกี่ยวข้องหลายกระบวนการโดยโหลด DLL/ไลบรารีที่ใช้ร่วมกันเดียวกัน OS ที่ฉันกังวลคือ Linux และ Windows แต่ก็มี Mac ในระดับที่น้อยกว่าเช่นกัน ฉันคิดว่าคำตอบสำหรับคำถามของฉันจะเหมือนกันสำหรับระบบปฏิบัติการทั้งหมด

ฉันสนใจเป็นพิเศษเกี่ยวกับการเชื่อมโยงอย่างชัดเจน แต่ฉันก็อยากรู้เกี่ยวกับการเชื่อมโยงโดยนัยด้วย ฉันคิดว่าคำตอบสำหรับทั้งสองจะเหมือนกันเช่นกัน

นี่เป็นคำอธิบายที่ดีที่สุดที่ฉันพบเกี่ยวกับ Windows:

ระบบจะรักษาจำนวนการอ้างอิงต่อกระบวนการในโมดูลที่โหลดทั้งหมด การเรียก LoadLibrary จะเพิ่มจำนวนการอ้างอิง การเรียกฟังก์ชัน FreeLibrary หรือ FreeLibraryAndExitThread จะลดจำนวนการอ้างอิง ระบบจะยกเลิกการโหลดโมดูลเมื่อจำนวนการอ้างอิงถึงศูนย์หรือเมื่อกระบวนการยุติลง (โดยไม่คำนึงถึงจำนวนการอ้างอิง) - http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx

แต่มันก็ทิ้งคำถามไว้บ้าง

1.) ทำกระบวนการที่ไม่เกี่ยวข้องโหลด DLL เดียวกันซ้ำซ้อน (นั่นคือ DLL มีอยู่ในหน่วยความจำมากกว่าหนึ่งครั้ง) แทนที่จะใช้การนับการอ้างอิงหรือไม่ (IE ลงในพื้นที่ที่อยู่ของแต่ละกระบวนการตามที่ฉันคิดว่าฉันเข้าใจ)

ถ้า DLL ถูกยกเลิกการโหลดทันทีที่กระบวนการสิ้นสุดลง นั่นทำให้ฉันเชื่อว่ากระบวนการอื่นๆ ที่ใช้ DLL เดียวกันทุกประการจะมีการโหลดซ้ำซ้อนลงในหน่วยความจำ มิฉะนั้น ระบบไม่ควรได้รับอนุญาตให้เพิกเฉยต่อจำนวนการอ้างอิง

2.) หากเป็นเช่นนั้นจริง จุดอ้างอิงในการนับ DLLs เมื่อคุณโหลดหลายครั้งในกระบวนการเดียวกันคืออะไร การโหลด DLL เดียวกันสองครั้งในกระบวนการเดียวกันจะมีประโยชน์อะไร เหตุผลเดียวที่เป็นไปได้ที่ฉันคิดได้ก็คือ ถ้า EXE อ้างอิงถึง DLL สองตัว และ DLL ตัวหนึ่งอ้างอิงถึงอีกตัวหนึ่ง ก็จะมีการเรียก LoadLibrar() อย่างน้อยสองครั้งและการเรียก FreeLibrary() สองครั้งสำหรับไลบรารีเดียวกัน

ฉันรู้ว่าดูเหมือนว่าฉันกำลังตอบคำถามของตัวเองที่นี่ แต่ฉันแค่ตั้งสมมุติฐานเท่านั้น ฉันอยากจะรู้ให้แน่ชัด


person Brandon    schedule 28.06.2013    source แหล่งที่มา
comment
ตรวจสอบให้แน่ใจว่าคุณเข้าใจหน่วยความจำเสมือนและเพจ ที่อยู่จริงที่กระบวนการเห็นอาจแตกต่างกันไม่ว่าจะมีการโหลดสำเนาไลบรารีแยกต่างหากหรือไม่ก็ตาม   -  person Kerrek SB    schedule 29.06.2013


คำตอบ (1)


ไลบรารีที่ใช้ร่วมกันหรือ DLL จะถูกโหลดหนึ่งครั้งสำหรับส่วนของโค้ด และหลายครั้งสำหรับส่วนข้อมูลที่เขียนได้ใดๆ [อาจผ่านทาง "copy-on-write" ดังนั้นหากคุณมีหน่วยความจำขนาดใหญ่ซึ่งส่วนใหญ่จะอ่าน แต่บางส่วนมีขนาดเล็ก ส่วนที่กำลังเขียนอยู่ DLL ทั้งหมดสามารถใช้ส่วนเดียวกันได้ตราบใดที่ไม่ได้เปลี่ยนจากค่าเดิม]

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

จุดอ้างอิงในการนับทุกโหลดคือช่วยให้ระบบรู้ว่าเมื่อใดจึงจะปลอดภัยที่จะยกเลิกการโหลดโมดูล (เมื่อจำนวนอ้างอิงเป็นศูนย์) หากเรามีสองส่วนที่แตกต่างกันของระบบ ทั้งสองส่วนต้องการใช้ DLL เดียวกัน และทั้งสองโหลด DLL นั้น คุณคงไม่ต้องการให้ระบบหยุดทำงานเมื่อส่วนแรกของระบบปิด DLL แต่เราไม่ต้องการให้ DLL อยู่ในหน่วยความจำเมื่อส่วนที่สองของระบบปิด DLL เนื่องจากจะทำให้หน่วยความจำเปลือง [ลองนึกภาพว่าแอปพลิเคชันนี้เป็นกระบวนการที่ทำงานบนเซิร์ฟเวอร์ และ DLL ใหม่จะถูกดาวน์โหลดจากเซิร์ฟเวอร์ทุกสัปดาห์ ดังนั้นในแต่ละสัปดาห์ DLL "ล่าสุด" (ซึ่งมีชื่อแตกต่างกัน) จะถูกโหลด หลังจากนั้นไม่กี่เดือน คุณจะมีหน่วยความจำทั้งหมดเต็มไปด้วย DLL's "เก่าและไม่ได้ใช้" ของแอปพลิเคชันนี้] แน่นอนว่ายังมีสถานการณ์ต่างๆ เช่น สิ่งที่คุณอธิบาย โดยที่ DLL โหลด DLL อื่นโดยใช้การเรียก LoadLibrary และไฟล์ปฏิบัติการหลักจะโหลด DLL เดียวกัน อีกครั้ง คุณต้องเรียก FreeLibrary สองครั้งเพื่อปิด

person Mats Petersson    schedule 28.06.2013
comment
ฉันไม่เข้าใจว่าคุณหมายถึงอะไรเกี่ยวกับส่วนข้อมูลที่เขียนได้หรือการคัดลอกเมื่อเขียน ฉันเข้าใจการนับการอ้างอิง สิ่งที่ทำให้ฉันผิดหวังคือส่วนหนึ่งของลิงก์ที่บอกว่า ระบบจะยกเลิกการโหลดโมดูลเมื่อจำนวนการอ้างอิงถึงศูนย์หรือเมื่อกระบวนการยุติ (โดยไม่คำนึงถึงจำนวนการอ้างอิง) . - person Brandon; 29.06.2013
comment
ใช่แล้ว มีการนับการอ้างอิงต่อกระบวนการและการนับการอ้างอิงอื่นของจำนวนกระบวนการที่ใช้ DLL เฉพาะ หากกระบวนการยุติ (การเรียก exit หรือขัดข้องในทางใดทางหนึ่ง) ดังนั้นจำนวนการอ้างอิงต่อกระบวนการจะไม่ถูกใช้เพื่อกำหนดข้อมูล ส่วนข้อมูลที่เขียนได้ - ตัวแปรส่วนกลางใน DLL จะต้องเป็นไปตามกระบวนการ ไม่เช่นนั้นอาจเป็นการรั่วไหลที่อันตรายระหว่างกระบวนการ ค้นหาใน google copy-on-write มันจะอธิบายได้ดีกว่าที่ฉันสามารถทำได้ในโพสต์ที่นี่ - person Mats Petersson; 29.06.2013
comment
เนื่องจากการโหลดครั้งก่อน ให้ใช้ที่อยู่ฐานเดียวกัน @MatsPetersson ฉันค่อนข้างสับสนกับสิ่งนี้ ระบบปฏิบัติการใช้ที่อยู่จริงใช่ไหม และระบบปฏิบัติการสามารถให้ที่อยู่เสมือนที่แตกต่างกันสำหรับ DLL สองตัวได้ หากกระบวนการใช้ทั้งสองอย่าง แล้วทำไมพวกมันถึงเหมือนกัน? - person pooya13; 10.02.2020
comment
หากมีการโหลด DLL สองครั้ง จะต้องโหลด (อย่างน้อยบางส่วน) ไปยังตำแหน่งทางกายภาพที่แตกต่างกัน หรือมีที่อยู่เสมือนเดียวกัน มีแนวโน้มว่าจะมีที่อยู่ที่แน่นอนบางส่วนที่เกี่ยวข้องกับโค้ด เช่น ตัวชี้ไปยังข้อมูลหรือฟังก์ชัน ที่ถูกเก็บไว้ที่ไหนสักแห่ง ซึ่งหมายความว่าที่อยู่เสมือนจะต้องเหมือนกันสำหรับผู้ใช้ทุกคนที่โหลด DLL ทางกายภาพ และโดยทั่วไประบบปฏิบัติการจะไม่ใช้ที่อยู่จริง โดยจะกำหนดที่อยู่เสมือนให้กับขอบเขตหน่วยความจำกายภาพ แต่นั่นเป็นเรื่องเกี่ยวกับการใช้ที่อยู่จริงเพียงครั้งเดียวเท่านั้น - person Mats Petersson; 11.02.2020