Огляд пам'яті програми

Програми виділяють пам'ять двома способами:

  • Стек: безперервна область пам'яті для локальних змінних.

    • Значення мають фіксовані розміри, відомі під час компіляції.
    • Надзвичайно швидко: просто перемістіть вказівник стека.
    • Легко керувати: слідує за викликами функцій.
    • Чудова локальність пам'яті.
  • Купа: Зберігання значень поза викликами функцій.

    • Значення мають динамічні розміри, визначені під час виконання.
    • Трохи повільніше, ніж стек: потрібн певний облік.
    • Немає гарантії локальності пам'яті.

Приклад

Створення String поміщає метадані фіксованого розміру в стек, а дані динамічного розміру, фактичний рядок, у купу:

fn main() {
    let s1 = String::from("Привіт");
}
StackHeaps1capacity5ptrHellolen5
This slide should take about 5 minutes.
  • Нагадайте, що тип String підтримується Vec, тому має ємність і довжину та може зростати, якщо мутабельна, через перерозподіл у купі.

  • Якщо студенти запитають про це, ви можете нагадати, що основна пам’ять розподіляється за допомогою System Allocator і користувальницькі розподільники можуть бути реалізовано за допомогою Allocator API

Більше інформації для вивчення

Ми можемо перевірити розташування пам’яті за допомогою unsafe Rust. Однак ви повинні зазначити, що це по праву небезпечно!

fn main() {
    let mut s1 = String::from("Привіт");
    s1.push(' ');
    s1.push_str("світ");
    // НЕ РОБІТЬ ЦЬОГО ВДОМА! Тільки в навчальних цілях.
    // String не надає жодних гарантій щодо своєї розмітки, тому це може призвести до
    // невизначеної поведінки.
    unsafe {
        let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1);
        println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}");
    }
}