بررسی حافظه برنامه

برنامه‌ها حافظه را به دو روش تخصیص می‌دهند:

  • Stack: بلوک پیوسته‌ای از حافظه که برای متغیرهای محلی (داخل یک تابع) استفاده می‌شود.

    • مقادیر دارای اندازه‌های ثابتی هستند که در زمان کامپایل شناخته می‌شوند.
    • بسیار سریع: فقط یک اشاره‌گر stack را جابجا کنید.
    • مدیریت آسان: پیرو فراخوانی‌های تابع است.
    • بهره‌وری عالی از حافظه.
  • Heap: ذخیره‌سازی مقادیر خارج از فراخوانی‌های تابع.

    • مقادیر دارای اندازه‌های پویا هستند که در زمان اجرا تعیین می‌شوند.
    • کمی کندتر از stack: نیاز به برخی از عملیات‌های مدیریتی دارد.
    • هیچ تضمینی برای بهره‌وری بالا از حافظه ندارد.

مثال

ساختن یک String metadata با اندازه ثابت را روی stack و داده با اندازه پویا، یعنی رشته واقعی، را روی heap قرار می‌دهد:

fn main() {
    let s1 = String::from("سلام");
}
StackHeaps1capacity5ptrHellolen5
This slide should take about 5 minutes.
  • ذکر کنید که یک String توسط یک Vec پشتیبانی می‌شود، بنابراین دارای ظرفیت و طول است و در صورت تغییرپذیری، می‌تواند از طریق اختصاص مجدد حافظه روی heap رشد کند.

  • اگر دانش‌آموزان درباره آن سوال کنند، می‌توانید اشاره کنید که حافظه زیرین با استفاده از System Allocator بر روی heap اختصاص داده شده و تخصیص‌دهنده‌های سفارشی می‌توانند با استفاده از Allocator API پیاده‌سازی شوند

برای کاوش بیشتر

می‌توانیم با استفاده از Rust ناامن (unsafe) نحوه چیدمان حافظه را بررسی کنیم. با این حال، باید اشاره کنید که این کار به درستی ناامن است!

fn main() {
    let mut s1 = String::from("سلام");
    s1.push(' ');
    s1.push_str("دنیا");
    // DON'T DO THIS AT HOME! For educational purposes only.
    // String provides no guarantees about its layout, so this could lead to
    // undefined behavior.
    unsafe {
        let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1);
        println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}");
    }
}