MemoryLayout และการจัดแนว
ตรวจสอบขนาด ระยะก้าว และการจัดแนวของชนิดต่าง ๆ
MemoryLayout และการจัดแนว เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดโครงสร้างหน่วยความจำจึงสำคัญ
เมื่อคุณทำงานกับสวิฟต์แบบไม่ปลอดภัยหรือเชื่อมต่อกับ C คุณจำเป็นต้องรู้ว่าค่าต่าง ๆ ถูกจัดเรียงในหน่วยความจำอย่างไร สวิฟต์มี MemoryLayout<T> ให้ใช้ตรวจสอบเรื่องนี้ได้โดยไม่ต้องแตะต้อง bytes แบบ raw
สิ่งนี้ตอบคำถามสามข้อ ได้แก่ ค่าหนึ่งค่ามีขนาดเท่าใด ค่าในอาร์เรย์อยู่ห่างกันเท่าใด และค่าต้องเริ่มต้นบนขอบเขตที่อยู่แบบใด
// MemoryLayout works on any type
print(MemoryLayout<Int>.size) // 8 on 64-bit
print(MemoryLayout<Bool>.size) // 1
print(MemoryLayout<Double>.size) // 8size — พื้นที่จัดเก็บจริง
MemoryLayout<T>.size คือจำนวนไบต์ที่ข้อมูลสำคัญของค่าหนึ่งค่าใช้พื้นที่ โดยไม่รวมส่วนเติมเต็มท้ายที่อาจอยู่ระหว่างสมาชิกในอาร์เรย์
ใช้ size เมื่อคุณต้องการทราบว่าค่าหนึ่งค่ามีไบต์ที่มีความหมายอยู่กี่ไบต์
struct Point {
var x: Int8 // 1 byte
var y: Int64 // 8 bytes
}
print(MemoryLayout<Point>.size) // 16 (not 9 — padding!)stride — การเว้นระยะในอาร์เรย์
stride คือระยะห่างเป็นไบต์ระหว่างจุดเริ่มต้นของสมาชิกหนึ่งกับสมาชิกถัดไป เมื่อค่าต่าง ๆ ถูกจัดเรียงในอาร์เรย์ต่อเนื่อง ระยะนี้เท่ากับ size ที่ปัดขึ้นตามค่า alignment
เมื่อคุณจัดสรรบัฟเฟอร์ด้วยตนเอง ให้คูณด้วย stride และอย่าคูณด้วย size
print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride) // 1
// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160alignment — ขอบเขตของที่อยู่
alignment คือขอบเขตของไบต์ที่ค่าต้องเริ่มต้น ค่าแบบจำนวนเต็ม 64 บิตที่มี alignment เท่ากับ 8 ต้องเริ่มต้นที่ที่อยู่ซึ่งหารด้วย 8 ลงตัว คอมไพเลอร์จะใส่ส่วนเติมเต็มเพื่อให้เป็นไปตามเงื่อนไขนี้
alignment ของโครงสร้างคือค่า alignment ที่มากที่สุดในบรรดาสมาชิกของโครงสร้าง
print(MemoryLayout<Int8>.alignment) // 1
print(MemoryLayout<Int64>.alignment) // 8
print(MemoryLayout<Point>.alignment) // 8ความแตกต่างระหว่าง size กับ stride
สำหรับชนิดข้อมูลจำนวนมาก size == stride แต่ทั้งสองค่าจะแตกต่างกันเมื่อมีส่วนเติมเต็ม โครงสร้างหนึ่งอาจมี size เท่ากับ 9 แต่มี stride เท่ากับ 16 เพราะสมาชิกถัดไปต้องจัดแนวให้ตรงกับขอบเขต 8 ไบต์
หลักจำง่าย: ใช้ size เพื่อพิจารณาค่าเดียว และใช้ stride เพื่อพิจารณากลุ่มข้อมูล
struct Mixed {
var flag: Bool // 1
var value: Int // 8
}
print(MemoryLayout<Mixed>.size) // 16
print(MemoryLayout<Mixed>.stride) // 16ออฟเซ็ตของฟิลด์
สำหรับโครงสร้าง คุณสามารถตรวจสอบได้ว่าคุณสมบัติที่จัดเก็บไว้แต่ละรายการอยู่ห่างจากจุดเริ่มต้นเท่าใด โดยใช้ MemoryLayout<T>.offset(of:) ร่วมกับเส้นทางคีย์ วิธีนี้จำเป็นเมื่อต้องจัดวางข้อมูลให้ตรงกับโครงสร้างข้อมูลของ C
struct Header {
var magic: UInt32 // offset 0
var length: UInt64 // offset 8 (padded)
}
print(MemoryLayout<Header>.offset(of: \Header.magic) ?? -1) // 0
print(MemoryLayout<Header>.offset(of: \Header.length) ?? -1) // 8การจัดลำดับใหม่เพื่อประหยัดพื้นที่
เนื่องจาก alignment ลำดับของคุณสมบัติที่จัดเก็บไว้จึงมีผลต่อ size การวางฟิลด์ขนาดใหญ่ไว้ก่อนหรือจัดกลุ่มตามขนาดอาจช่วยลดขนาดโครงสร้างได้ เรื่องนี้สำคัญสำหรับอาร์เรย์ขนาดใหญ่ เพราะไบต์ที่สูญเปล่าจะสะสมเพิ่มขึ้น
struct Wasteful { var a: Int8; var b: Int64; var c: Int8 } // size 24
struct Tight { var b: Int64; var a: Int8; var c: Int8 } // size 16
print(MemoryLayout<Wasteful>.size)
print(MemoryLayout<Tight>.size)โครงสร้างของการอ้างอิง
อินสแตนซ์ของคลาสถูกจัดสรรบนฮีพ ดังนั้นตัวแปรที่เก็บการอ้างอิงไปยังคลาสจึงเป็นเพียงตัวชี้ ค่า MemoryLayout.size ของตัวแปรนี้มีขนาดเท่ากับตัวชี้ หรือ 8 ไบต์ ไม่ว่าออบเจ็กต์จะมีขนาดเท่าใด
ชนิดค่าอย่างโครงสร้างจะเก็บเนื้อหาไว้ภายในตัวมันเอง ส่วนชนิดอ้างอิงจะเก็บไว้เพียงตัวชี้
class Big { var data = [Int](repeating: 0, count: 1000) }
print(MemoryLayout<Big>.size) // 8 — just the referenceออปชันนัลและอีนัม
ออปชันนัลมักเพิ่มหนึ่งไบต์สำหรับแท็ก แต่สวิฟต์จะปรับออปชันนัลของการอ้างอิงให้ใช้ตัวชี้ว่างร่วมกัน จึงทำให้ชนิดสตริงแบบออปชันนัลอาจมีขนาดเท่ากับชนิดสตริงปกติ
อีนัมที่มีค่าที่เชื่อมโยงจะมีขนาดพอสำหรับกรณีที่ใหญ่ที่สุด รวมกับตัวจำแนก
print(MemoryLayout<Int?>.size) // 9
print(MemoryLayout<String>.size) // 16
print(MemoryLayout<String?>.size) // 16 — no extra byteการใช้รูปแบบอินสแตนซ์ของ:
สมาชิกทุกตัว ได้แก่ size, stride และ alignment ต่างก็มีรูปแบบที่อิงจากอินสแตนซ์ เช่น MemoryLayout.size(ofValue:) รูปแบบนี้มีประโยชน์เมื่อเขียนระบุชนิดได้ยาก หรือเมื่อชนิดถูกอนุมานโดยอัตโนมัติ
let tuple = (UInt8(1), UInt64(2))
print(MemoryLayout.size(ofValue: tuple)) // 16
print(MemoryLayout.stride(ofValue: tuple)) // 16
print(MemoryLayout.alignment(ofValue: tuple)) // 8การจัดสรรด้วยโครงสร้างที่ถูกต้อง
เมื่อคุณ allocate หน่วยความจำ raw คุณต้องส่งทั้งจำนวนไบต์และค่า alignment การดึงค่าเหล่านี้จาก MemoryLayout ช่วยรับรองความถูกต้องในสถาปัตยกรรมต่าง ๆ แทนการกำหนดตัวเลขตายตัว
let count = 4
let capacity = count * MemoryLayout<Int>.stride
let align = MemoryLayout<Int>.alignment
let raw = UnsafeMutableRawPointer.allocate(
byteCount: capacity, alignment: align)
defer { raw.deallocate() }ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจเกี่ยวกับความแตกต่างระหว่าง size กับ stride
สรุปทบทวน
คุณได้เรียนรู้หลักสามประการของโครงสร้างหน่วยความจำ:
- size — ไบต์ที่มีความหมายของค่าหนึ่งค่า
- stride — ระยะห่างระหว่างสมาชิกในอาร์เรย์ ใช้ค่านี้เมื่อต้องจัดสรรหน่วยความจำ
- alignment — ขอบเขตเริ่มต้นที่จำเป็น
คุณยังได้เห็น offset(of:) สำหรับระบุตำแหน่งของฟิลด์ ได้เรียนรู้ว่าลำดับของคุณสมบัติมีผลต่อ size และเห็นว่าการอ้างอิงมีขนาดเท่ากับตัวชี้เท่านั้น เครื่องมือเหล่านี้ช่วยให้คุณจัดสรรและแปลความหมายหน่วยความจำ raw ได้อย่างปลอดภัย
คำถามที่พบบ่อย
บทเรียน “MemoryLayout และการจัดแนว” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “MemoryLayout และการจัดแนว” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “MemoryLayout และการจัดแนว”
ตรวจสอบขนาด ระยะก้าว และการจัดแนวของชนิดต่าง ๆ คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “MemoryLayout และการจัดแนว” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม
ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- MemoryLayout และการจัดแนว
- UnsafePointer และ UnsafeMutablePointer
- ตัวชี้บัฟเฟอร์ที่ไม่ปลอดภัย
- withUnsafeBytes และการทำงานร่วมกับ C