0Pricing
Swift Academy · درس

‏MemoryLayout والمحاذاة

افحص الحجم والخطوة والمحاذاة للأنواع.

‏MemoryLayout والمحاذاة درس مجاني في Swift Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Swift Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Swift Academy 4 دروس في المجموع.

أهمية تخطيط الذاكرة

عند العمل باستخدام Swift غير الآمن أو الربط مع C، تحتاج إلى معرفة كيفية ترتيب القيم في الذاكرة. يوفّر لك Swift النوع MemoryLayout<T> لفحص ذلك دون لمس البايتات الخام.

ويجيب عن ثلاثة أسئلة: ما حجم القيمة، وما المسافة بين القيم في المصفوفة، وعلى أي حدّ للعناوين يجب أن تبدأ القيمة.

// MemoryLayout works on any type
print(MemoryLayout<Int>.size)       // 8 on 64-bit
print(MemoryLayout<Bool>.size)      // 1
print(MemoryLayout<Double>.size)    // 8

size — التخزين الفعلي

يمثّل 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 بعد تقريبه إلى أعلى حدّ للمحاذاة.

عند تخصيص المخازن يدويًا، اضرب في stride، وليس في size أبدًا.

print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Int8>.stride)  // 1

// Buffer for 10 Points needs:
let bytes = 10 * MemoryLayout<Point>.stride // 160

alignment — حدود العناوين

يمثّل alignment حدّ البايت الذي يجب أن تبدأ عنده القيمة. يجب أن يبدأ Int64 ذو محاذاة مقدارها 8 عند عنوان يقبل القسمة على 8. ويُدرج المصرّف حشوًا للالتزام بذلك.

تساوي محاذاة البنية أكبر محاذاة بين أعضائها.

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

إعادة الترتيب لتوفير المساحة

بسبب المحاذاة، يؤثر ترتيب الخصائص المخزنة في الحجم. ويمكن أن يؤدي وضع الحقول الأكبر أولًا أو تجميع الحقول حسب الحجم إلى تقليص حجم البنية. ويكتسب ذلك أهمية في المصفوفات الكبيرة، حيث تتراكم البايتات المهدرة.

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

الأنواع الاختيارية والتعدادات

تضيف الأنواع الاختيارية عادةً بايتًا واحدًا للوسم، لكن Swift يحسّن المراجع الاختيارية بإعادة استخدام المؤشر الفارغ، لذلك قد يكون حجم String? مساويًا لحجم String.

تُحدَّد أحجام التعدادات ذات القيم المرتبطة بما يكفي لاستيعاب أكبر حالة فيها، بالإضافة إلى مميّز.

print(MemoryLayout<Int?>.size)    // 9
print(MemoryLayout<String>.size)  // 16
print(MemoryLayout<String?>.size) // 16 — no extra byte

استخدام of: مع مثيل

لكل عضو، مثل 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

التخصيص باستخدام التخطيط الصحيح

عند تخصيص الذاكرة الخام، يجب تمرير عدد البايتات والمحاذاة معًا. ويضمن الحصول عليهما من 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:) لتحديد مواضع الحقول، وكيف يؤثر ترتيب الخصائص في الحجم، وأن المراجع لا يتجاوز حجمها حجم المؤشر. تتيح لك هذه الأدوات تخصيص الذاكرة الخام وتفسيرها بأمان.

الأسئلة الشائعة

هل درس «‏MemoryLayout والمحاذاة» مجاني؟

نعم — نص درس «‏MemoryLayout والمحاذاة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Swift Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Swift Academy 4 دروس في المجموع.

ماذا ستتعلم في «‏MemoryLayout والمحاذاة»؟

افحص الحجم والخطوة والمحاذاة للأنواع. تتمرن على Swift Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Swift Academy؟

لا تُشترط خبرة سابقة. Swift Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «‏MemoryLayout والمحاذاة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Swift Academy هذا؟

نعم. كل درس في Swift Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. ‏MemoryLayout والمحاذاة
  2. ‏UnsafePointer و UnsafeMutablePointer
  3. مؤشرات المخازن المؤقتة غير الآمنة
  4. ‏withUnsafeBytes والتكامل مع C
← العودة إلى Swift Academy