إدارة الذاكرة في Rust: لماذا لا يوجد جامع قمامة وكيف يعمل ذلك

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

ما هو جامع القمامة ولماذا تخلى عنه Rust؟

\n\n

إذا كنت قادماً من عالم Python أو Java أو C#، فأنت معتاد على أن الذاكرة تُدار بواسطة جامع القمامة (Garbage Collector, GC). إنه "منظف" غير مرئي يتحقق بشكل دوري من الكائنات التي لم تعد مستخدمة، ويحرر الذاكرة التي تشغلها. مريح؟ نعم. لكن هناك تفاصيل:

\n\n
    \n
  • توقفات غير متوقعة. قد يعمل GC في أكثر الأوقات غير المناسبة — عندما يعالج كودك طلباً مهماً أو يعرض إطاراً في لعبة.
  • \n
  • استهلاك إضافي للذاكرة. غالباً ما يتطلب GC ذاكرة إضافية لعمله.
  • \n
  • صعوبة في الأنظمة الزمنية الحقيقية. في أنظمة التشغيل أو برامج التشغيل أو الأجهزة المدمجة، تكون توقفات GC غير مقبولة.
  • \n
\n\n

يقدم Rust نهجاً مختلفاً جذرياً. بدلاً من جامع القمامة، يتم استخدام نظام الملكية (ownership) الذي يعمل في مرحلة التجميع. المترجم هو من يقرر متى يجب تحرير الذاكرة، ويفعل ذلك بدون أي عبء زمني للتشغيل (runtime overhead). دعنا نفهم كيف يعمل ذلك.

\n\n

نظام الملكية (Ownership) — أساس إدارة الذاكرة

\n\n

في Rust، لكل قيمة مالك واحد بالضبط — المتغير الذي تمتلكه هذه القيمة. عندما يخرج المالك عن النطاق (scope)، يتم تحرير الذاكرة تلقائياً. لا جامع قمامة، لا عد مرجعي — فقط المترجم وقواعد صارمة.

\n\n

قواعد الملكية في Rust

\n\n

إليك ثلاث قواعد رئيسية يتحقق منها المترجم في مرحلة التجميع:

\n\n
    \n
  • لكل قيمة في Rust مالك واحد.
  • \n
  • عندما يخرج المالك عن النطاق، يتم حذف القيمة (drop).
  • \n
  • يمكن نقل القيمة إلى مالك آخر (move) أو استعارتها (borrow).
  • \n
\n\n
fn main() {\n    let s1 = String::from("Hello"); // s1 — مالك السلسلة النصية\n    let s2 = s1;                     // الملكية تنتقل إلى s2 (move)\n    // println!("{}", s1);           // خطأ! s1 لم يعد يملك السلسلة النصية\n    println!("{}", s2);             // صحيح: s2 هو المالك الجديد\n} // هنا يخرج كل من s1 و s2 عن النطاق،\n  // لكن الذاكرة تُحرر مرة واحدة فقط — لـ s2
\n\n

في Python أو Java، كنت ستقوم ببساطة بإنشاء مرجع آخر للكائن، وكان GC سيتعامل معه لاحقاً. في Rust — لا مفاجآت: المترجم يضمن تحرير الذاكرة مرة واحدة بالضبط.

\n\n

الاقتراض (Borrowing) — كيفية استخدام البيانات دون نقل الملكية

\n\n

غالباً ما نحتاج إلى "استعارة" الوصول إلى البيانات بشكل مؤقت، دون أخذها من المالك. لهذا، في Rust مراجع (references). وهي من نوعين:

\n\n
    \n
  • المراجع غير القابلة للتغيير (&T): يمكن قراءة البيانات، لكن لا يمكن تعديلها.
  • \n
  • المراجع القابلة للتغيير (&mut T): يمكن القراءة والتعديل، لكن فقط إذا لم تكن هناك مراجع نشطة أخرى.
  • \n
\n\n
fn main() {\n    let mut text = String::from("Rust");\n    \n    let r1 = &text;     // مرجع غير قابل للتغيير\n    let r2 = &text;     // مرجع غير قابل للتغيير آخر — مسموح\n    println!("{} {}", r1, r2);\n    \n    let r3 = &mut text; // مرجع قابل للتغيير — يعمل، لأن r1 و r2 لم يعودا مستخدمين\n    r3.push_str(" rocks!");\n    println!("{}", r3);\n    \n    // لكن هذا غير مسموح:\n    // let r1 = &text;\n    // let r3 = &mut text; // خطأ! لا يمكن وجود مرجع قابل للتغيير وآخر غير قابل للتغيير في نفس الوقت\n}
\n\n

مترجم Rust ليس مجرد محلل ثابت، إنه معلم صارم لكن عادل. لن يسمح لك بإطلاق النار على قدمك. إذا حاولت إنشاء مرجع قابل للتغيير بينما توجد مراجع غير قابلة للتغيير — ستحصل على خطأ في التجميع. هذا هو عمل borrow checker — الآلية التي تحل محل

المدونات

توصيات الكتب