อะไรคือความแตกต่างระหว่าง vmalloc และ kmalloc?


114

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

GFP_ATOMIC
การจัดสรรมีความสำคัญสูงและไม่ได้นอนหลับ นี่คือแฟล็กที่จะใช้ในตัวจัดการขัดจังหวะครึ่งล่างและสถานการณ์อื่น ๆ ที่คุณนอนไม่หลับ

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


บทความดีๆเกี่ยวกับ vmalloc และ kmalloc http://learnlinuxconcepts.blogspot.in/2014/02/linux-memory-management.html
JIN007

4
บทความนั้นอ้างว่าไร้สาระเช่น "โดยทั่วไปสถาปัตยกรรม 32 บิตจะมีขนาดหน้า 4KB และสถาปัตยกรรม 64 บิตมีขนาดหน้า 8KB" ฉันอ่านไม่ครบ แต่จะไม่เรียกมันว่า "ดี" หรือแม้แต่จะเชื่อถือคำจากคำนั้น
Alexandro Sánchez

1
หมายเหตุ (กึ่งเกี่ยวข้อง): vmallocเร็วกว่าด้วย Kernel 5.2 (Q2 2019)
VonC

คำตอบ:


96

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

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

kmalloc มีข้อ จำกัด ในขนาดของบัฟเฟอร์ก็สามารถให้บริการ: 128 KBytes *) หากคุณต้องการบัฟเฟอร์ขนาดใหญ่จริงๆคุณต้องใช้ vmalloc หรือกลไกอื่น ๆ เช่นการสำรองหน่วยความจำสูงเมื่อบูต

*) นี่เป็นความจริงของเมล็ดพันธุ์ก่อนหน้านี้ ในเมล็ดล่าสุด (ฉันทดสอบสิ่งนี้เมื่อ 2.6.33.2) ขนาดสูงสุดของ kmalloc เดียวคือสูงสุด 4 MB! (ฉันเขียนโพสต์ที่ค่อนข้างละเอียดเกี่ยวกับเรื่องนี้ ) - kaiwan

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


1
ฉันคิดว่าการโทรของระบบถูกป้อนโดยการเรียก int $ 0x80? (คือการขัดจังหวะ)?
FreeMemory

2
int $ 0x80 เป็นการขัดจังหวะซอฟต์แวร์หรือที่เรียกว่ากับดัก สิ่งที่หมายถึงตัวจัดการขัดจังหวะคือการขัดจังหวะฮาร์ดแวร์เช่นเมื่อผู้ใช้กดแป้นหรือย้ายการเคลื่อนไหว
Branan

การเรียกระบบมีไว้สำหรับ userspace ไปยังการเปลี่ยนพื้นที่เคอร์เนล ... kmalloc ใช้ในบริบทเคอร์เนลเท่านั้น ??
AIB

3
@FreeMemory: int $ 0x80 เป็น x86 โดยเฉพาะและเป็นวิธีการเก่าที่แทนที่ด้วย sysenter / syscall (บน x86)
jørgensen

18

คำตอบสั้น ๆ : ดาวน์โหลดLinux Device Driversและอ่านบทเกี่ยวกับการจัดการหน่วยความจำ

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

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


1
"เพราะเคอร์เนลไม่ค่อยใช้หน่วยความจำเสมือน" ทำไมถึงเป็นเช่นนั้น?
Trey

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

ไม่หน่วยความจำเคอร์เนลที่จัดสรรด้วย vmalloc จะไม่ถูกสลับ สามารถสลับหน่วยความจำ userspace ได้เท่านั้น พื้นที่แอดเดรสเคอร์เนลไม่สามารถใช้งานได้และ vmalloc จัดสรรในพื้นที่แอดเดรสของเคอร์เนล
user2679859

14

การพัฒนาเคอร์เนลลินุกซ์โดย Robert Love (บทที่ 12 หน้า 244 ในรุ่นที่ 3) ตอบโจทย์นี้ได้อย่างชัดเจน

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

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


11

kmalloc()และvmalloc()ฟังก์ชั่นอินเตอร์เฟซที่เรียบง่ายสำหรับการได้รับหน่วยความจำเคอร์เนลใน chunks ไบต์ขนาด

  1. kmalloc()ค้ำประกันฟังก์ชั่นว่าหน้าเว็บที่มีความต่อเนื่องกันทางร่างกาย (และต่อเนื่องกันจริง)

  2. vmalloc()ฟังก์ชั่นการทำงานในลักษณะคล้ายกับkmalloc()นอกจากจะจัดสรรหน่วยความจำที่เป็นเพียงที่อยู่ติดกันจริงและไม่จำเป็นต้องต่อเนื่องกันทางร่างกาย


4

ข้อดีของการมีบล็อกหน่วยความจำที่ต่อเนื่องกันคืออะไร? โดยเฉพาะเหตุใดฉันจึงต้องมีบล็อกหน่วยความจำทางกายภาพที่ต่อเนื่องกันในการเรียกระบบ มีเหตุผลใดบ้างที่ฉันไม่สามารถใช้ vmalloc ได้?

จาก "I'm Feeling Lucky" ของ Google เมื่อvmalloc:

kmalloc เป็นวิธีที่ต้องการตราบใดที่คุณไม่ต้องการพื้นที่ขนาดใหญ่มาก ปัญหาคือถ้าคุณต้องการทำ DMA จาก / ไปยังอุปกรณ์ฮาร์ดแวร์บางตัวคุณจะต้องใช้ kmalloc และคุณอาจต้องการชิ้นส่วนที่ใหญ่กว่า วิธีแก้ปัญหาคือการจัดสรรหน่วยความจำโดยเร็วที่สุดก่อนที่หน่วยความจำจะแยกส่วน


ดูฉันอ่านแล้วและมันไม่สมเหตุสมผลสำหรับฉัน ฉันเข้าใจการใช้ kmalloc สำหรับพื้นที่ขนาดใหญ่ แต่สำหรับการจัดสรรขนาดเล็กทำไมไม่ใช้ vmalloc เพื่อหลีกเลี่ยงการแยกส่วนหน่วยความจำกายภาพ
FreeMemory

เพราะคุณควรไว้วางใจให้เคอร์เนลทำสิ่งที่ดีที่สุด ถ้าคิดว่าการจัดสรรก้อนเดียวดีกว่าก็จะทำเช่นนั้น vmalloc มีไว้สำหรับเมื่อคุณต้องมีชิ้นส่วนที่ต่อเนื่องกันเท่านั้น
Dark Shikari

ฉันเดาว่ามันสมเหตุสมผล แต่ดูเหมือนจะสวนทางกัน kmalloc ดูเหมือนว่าควรใช้เมื่อประสิทธิภาพเป็นสิ่งที่น่ากังวลมากที่สุด (เช่นฉันไม่สามารถถูกทำลายโดย disk IO) แล้ว GFP_ATOMIC ล่ะ
FreeMemory

2

บนระบบ 32 บิต kmalloc () จะส่งคืนที่อยู่โลจิคัลของเคอร์เนล (แม้ว่าจะเป็นที่อยู่เสมือน) ซึ่งมีการแม็ปโดยตรง (จริงด้วยค่าชดเชยคงที่) ไปยังที่อยู่ทางกายภาพ การทำแผนที่โดยตรงนี้ช่วยให้มั่นใจได้ว่าเราได้รับ RAM ทางกายภาพที่ต่อเนื่องกัน เหมาะสำหรับ DMA ที่เราให้เฉพาะตัวชี้เริ่มต้นและคาดว่าจะมีการทำแผนที่ทางกายภาพที่ต่อเนื่องกันหลังจากนั้นสำหรับการดำเนินการของเรา

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


1

ความแตกต่างอย่างหนึ่งคือ kmalloc จะส่งคืนที่อยู่ตรรกะ (อื่น ๆ ที่คุณระบุ GPF_HIGHMEM) ที่อยู่แบบลอจิคัลถูกวางไว้ใน "หน่วยความจำเหลือน้อย" (ในหน่วยความจำกายภาพหน่วยแรก) และแมปโดยตรงกับที่อยู่ทางกายภาพ (ใช้มาโคร __pa เพื่อแปลง) คุณสมบัตินี้หมายถึงหน่วยความจำ kmalloced คือหน่วยความจำต่อเนื่อง

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

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