ข้อดีของไฟล์ที่แมปหน่วยความจำคืออะไร?


90

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

โดยเฉพาะอย่างยิ่งฉันกังวลเกี่ยวกับสิ่งต่อไปนี้ตามลำดับความสำคัญ:

  • ภาวะพร้อมกัน
  • การเข้าถึงแบบสุ่ม
  • ประสิทธิภาพ
  • สะดวกในการใช้
  • การพกพา

คำตอบ:


57

ฉันคิดว่าข้อดีก็คือคุณลดปริมาณการคัดลอกข้อมูลที่ต้องใช้ในการอ่านไฟล์แบบเดิม ๆ

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

หากจำเป็นต้องอ่านข้อมูลจากแผ่นดิสก์จริง ๆ (เช่นเดียวกับ I / O ทางกายภาพ) ระบบปฏิบัติการยังคงต้องอ่านข้อมูลดังกล่าวความผิดพลาดของเพจอาจไม่มีประสิทธิภาพที่ดีไปกว่าการเรียกระบบ แต่ถ้า อย่า (เช่นอยู่ในแคชของระบบปฏิบัติการแล้ว) ในทางทฤษฎีประสิทธิภาพควรจะดีกว่ามาก

ในข้อเสียไม่มีอินเทอร์เฟซแบบอะซิงโครนัสไปยังไฟล์ที่แมปหน่วยความจำ - หากคุณพยายามเข้าถึงเพจที่ไม่ได้แมปไว้มันจะสร้างข้อผิดพลาดของเพจจากนั้นทำให้เธรดรอ I / O


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


4
ใน Windows อย่างน้อยคุณสามารถแมปมุมมอง 32 บิตของไฟล์ mmap ขนาดใหญ่ได้หลายครั้งซึ่งจะมีประสิทธิภาพมากกว่าการพยายามจัดการกับไฟล์ขนาดใหญ่โดยใช้ฟังก์ชัน CRT ปกติ
Martin Beckett

@MarkR คุณเขียนว่า "การคัดลอกพิเศษของเขาไม่เพียง แต่ต้องใช้เวลาเท่านั้น แต่ยังลดประสิทธิภาพของแคชของ CPU ด้วยการเข้าถึงสำเนาข้อมูลเพิ่มเติมนี้ด้วย " ( เน้นของฉัน) คุณช่วยอธิบายได้ไหมว่าบัฟเฟอร์สำเนาพิเศษในเคอร์เนลขัดขวางประสิทธิภาพของแคชของ CPU ได้อย่างไร
Geek

4
@Geek เข้าถึงหน่วยความจำมากเป็นสองเท่า = เสียแคชมากเป็นสองเท่า (โดยประมาณ)
user253751

50

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

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

  • ภาวะพร้อมกัน - ฉันมีปัญหาในการใช้งานซึ่งบางครั้งหน่วยความจำจะแมปไฟล์หลายครั้งในพื้นที่กระบวนการเดียวกัน นี่เป็นปัญหาในขณะที่ฉันจำได้เพราะบางครั้งระบบไม่พบบล็อกหน่วยความจำเสมือนที่ว่างมากพอที่จะแมปไฟล์ วิธีแก้ปัญหาคือการแมปไฟล์เพียงครั้งเดียวและตัดสายทั้งหมด ในการย้อนกลับไปใช้บริการ Windows แบบเต็มรูปแบบน่าจะดี
  • Random Access - การค้นหาแบบไบนารีเป็นการเข้าถึงแบบสุ่มและรวดเร็วทันใจ
  • ประสิทธิภาพ - การค้นหารวดเร็วมาก เมื่อผู้ใช้พิมพ์หน้าต่างป๊อปอัปจะแสดงรายการหมายเลขชิ้นส่วนผลิตภัณฑ์ที่ตรงกันรายการจะหดเล็กลงเมื่อพิมพ์ต่อไป ไม่มีอาการหน่วงอย่างเห็นได้ชัดขณะพิมพ์

1
การค้นหาแบบไบนารีจะไม่ช้าเนื่องจากมีการอ่านหน้าเว็บในแต่ละครั้งหรือไม่? หรือระบบปฏิบัติการฉลาดพอที่จะจัดการกับสิ่งนี้อย่างมีประสิทธิภาพหรือไม่?
jjxtra

1
ฉันคิดว่าการใช้หน่วยความจำ I / O ที่แมปเป็นเรื่องที่สิ้นเปลืองสำหรับการค้นหาแบบไบนารีเนื่องจากการค้นหาจะเข้าถึงคีย์เดียวเพียงไม่กี่คีย์ในตำแหน่งหน่วยความจำที่ค่อนข้างห่างไกล แต่ระบบปฏิบัติการจะโหลดหน้า 4k สำหรับแต่ละคำขอดังกล่าว แต่แล้วอีกครั้งไฟล์ที่มีส่วนต่างๆไม่ได้เปลี่ยนแปลงมากนักดังนั้นแคชจึงช่วยปกปิดสิ่งนี้ได้ แต่พูดอย่างเคร่งครัดฉันเชื่อว่าการแสวงหา / การอ่านแบบดั้งเดิมจะดีกว่าที่นี่ ในที่สุดวันนี้ 1 ล้านบาทก็ไม่มาก ทำไมไม่เก็บมันทั้งหมดไว้ใน RAM?
สุกร

5
@ the swine and PsychoDad คำตอบเดิมของฉันคือตั้งแต่ปี 2008 และการใช้งานจริงของคุณสมบัติการเติมข้อมูลอัตโนมัติที่แมปนี้อยู่ในช่วงประมาณปี 2004-2005 หรือมากกว่านั้น การใช้หน่วยความจำกายภาพ 800-1000MB ในการโหลดไฟล์ทั้งหมดไม่ใช่ทางออกที่ดีสำหรับฐานผู้ใช้ของเรา โซลูชันการแมปหน่วยความจำนั้นรวดเร็วและมีประสิทธิภาพมาก มันเตะตูดและฉันจำได้ด้วยความรักตั้งแต่สมัยยังเป็นนักพัฒนาซอฟต์แวร์รุ่นแรก ๆ ของฉัน :)
Brian Ensink

@BrianEnsink: โอเคมันสมเหตุสมผลแล้ว ฉันไม่ได้คาดหวังว่าแต่ละรายการจะมากถึง 1kB แน่นอนว่าวิธีการเพจจะมีประสิทธิภาพมากขึ้น ดี :)
สุกร

consuming physical memory to load the entire file was not a good solution. ฉันไม่แน่ใจว่าทำไมคุณถึงกังวลกับหน่วยความจำกายภาพ (การโหลดไฟล์ลงใน byteBuffer ใช้หน่วยความจำกายภาพมากกว่าหรือไม่นั่นคือรายละเอียดของระบบปฏิบัติการ) mmap จะใช้พื้นที่ทั้งหมดในหน่วยความจำเสมือนและการอ่านไฟล์ตามไบต์เฉพาะที่คุณไม่ต้องการ กล่าวถึงthe swine But strictly speaking, i believe that traditional seeking/reading would be better in here.นั่นเป็นความคิดที่น่าสนใจเพราะคุณสามารถอ่านไบต์ที่คุณต้องการเมื่อคุณต้องการได้อย่างแท้จริง
Ben Butterworth

22

ไฟล์ที่แมปหน่วยความจำสามารถใช้เพื่อแทนที่การเข้าถึงแบบอ่าน / เขียนหรือเพื่อรองรับการแชร์พร้อมกัน เมื่อคุณใช้มันสำหรับกลไกหนึ่งคุณจะได้รับกลไกอื่นเช่นกัน

แทนที่จะมองและเขียนและอ่านในไฟล์คุณจะแมปมันลงในหน่วยความจำและเข้าถึงบิตที่คุณคาดหวังไว้

สิ่งนี้มีประโยชน์มากและขึ้นอยู่กับอินเทอร์เฟซหน่วยความจำเสมือนสามารถปรับปรุงประสิทธิภาพได้ การปรับปรุงประสิทธิภาพอาจเกิดขึ้นได้เนื่องจากตอนนี้ระบบปฏิบัติการได้รับการจัดการ "ไฟล์ I / O" เดิมนี้พร้อมกับการเข้าถึงหน่วยความจำแบบโปรแกรมอื่น ๆ ทั้งหมดของคุณและ (ในทางทฤษฎี) สามารถใช้ประโยชน์จากอัลกอริทึมการเพจและอื่น ๆ ที่ใช้เพื่อสนับสนุนอยู่แล้ว หน่วยความจำเสมือนสำหรับโปรแกรมที่เหลือของคุณ อย่างไรก็ตามมันขึ้นอยู่กับคุณภาพของระบบหน่วยความจำเสมือนของคุณ เกร็ดเล็กเกร็ดน้อยที่ฉันเคยได้ยินบอกว่าระบบหน่วยความจำเสมือน Solaris และ * BSD อาจแสดงการปรับปรุงประสิทธิภาพที่ดีกว่าระบบ VM ของ Linux - แต่ฉันไม่มีข้อมูลเชิงประจักษ์ที่จะสำรองข้อมูลนี้ YMMV.

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

ในโลกที่มีแผนที่ตรงกันข้ามให้จินตนาการถึงกระบวนการสองกระบวนการทั้ง "การเขียน" พวกเขาทำได้โดยการทำ "ที่เก็บหน่วยความจำ" ซึ่งส่งผลให้ O / S เพจข้อมูลออกไปยังดิสก์ - ในที่สุด แต่ในระหว่างนี้การเขียนทับซ้อนกันอาจเกิดขึ้นได้

นี่คือตัวอย่าง สมมติว่าฉันมีสองกระบวนการทั้งเขียน 8 ไบต์ที่ออฟเซ็ต 1024 กระบวนการที่ 1 กำลังเขียน "11111111" และกระบวนการที่ 2 กำลังเขียน "22222222" หากพวกเขาใช้ไฟล์ I / O คุณจะนึกออกว่าลึกลงไปใน O / S มีบัฟเฟอร์ที่เต็มไปด้วย 1s และบัฟเฟอร์เต็มไปด้วย 2 วินาทีทั้งสองมุ่งหน้าไปยังที่เดียวกันบนดิสก์ หนึ่งในนั้นจะไปถึงที่นั่นก่อนและอีกหนึ่งวินาที ในกรณีนี้คนที่สองจะชนะ อย่างไรก็ตามหากฉันใช้วิธีการแมปไฟล์หน่วยความจำกระบวนการที่ 1 จะไปที่หน่วยความจำขนาด 4 ไบต์ตามด้วยที่เก็บหน่วยความจำอีก 4 ไบต์ (สมมติว่าไม่ใช่ขนาดหน่วยความจำสูงสุด) กระบวนการที่ 2 จะทำสิ่งเดียวกัน ขึ้นอยู่กับเวลาที่กระบวนการทำงานคุณสามารถคาดหวังว่าจะเห็นสิ่งต่อไปนี้:

11111111
22222222
11112222
22221111

วิธีแก้ปัญหานี้คือการใช้การกีดกันซึ่งกันและกันอย่างชัดเจนซึ่งอาจเป็นความคิดที่ดีในทุกกรณี คุณต้องอาศัย O / S เพื่อทำ "สิ่งที่ถูกต้อง" ในกรณี I / O ของไฟล์อ่าน / เขียน

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

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


1

ภาวะพร้อมกันจะเป็นปัญหา การเข้าถึงโดยสุ่มนั้นง่ายกว่าประสิทธิภาพดีถึงดีมาก สะดวกในการใช้. ไม่ดีเท่า. พกพา - ไม่ร้อน

ฉันเคยใช้มันในระบบดวงอาทิตย์เมื่อนานมาแล้วและนั่นคือความคิดของฉัน

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