Понимание утечки памяти с R c в ржавчине - PullRequest
1 голос
/ 13 апреля 2020

Если мы посмотрим на следующий код ( ссылка на игровую площадку ):

use std::cell::RefCell;
use std::rc::Rc;

struct Person {
    name: String,
    parent: Option<Rc<RefCell<Person>>>,
    child: Option<Rc<RefCell<Person>>>,
}

impl Drop for Person {
    fn drop(&mut self) {
        println!("dropping {}", &self.name);
    }
}

pub fn main() {
    let anakin = Rc::new(RefCell::new(Person {
        parent: None,
        child: None,
        name: "anakin".to_owned(),
    }));

    let luke = Rc::new(RefCell::new(Person {
        parent: None,
        child: None,
        name: "luke".to_owned(),
    }));

    luke.borrow_mut().parent = Some(anakin.clone());
    anakin.borrow_mut().child = Some(luke.clone());

    println!("anakin {}", Rc::strong_count(&anakin));
    println!("luke {}", Rc::strong_count(&luke));
}

При выполнении кода сообщение из реализации отбрасывания не печатается, поскольку предполагается, что этот код предполагается утечка памяти.

Когда код завершает подсчет для Люка и Анакина, он должен заканчиваться на 1, а не на 0 (то есть, когда данные управляемой кучи будут очищены).

Почему считать не в конечном итоге 0? Я бы подумал, что произойдет следующая последовательность:

  1. мы начнем с двух местоположений данных в куче, одно из которых указано luke и anakin.child, а другое - anakin и luke. родитель. Объекту luke принадлежит luke.parent. Объект anakin принадлежит anakin.child

  2. luke выходит из области видимости, что означает, что его члены, которыми он владеет, также удаляются. Так что Люк и Люк. Родитель, брось. Оба являются Rcs, поэтому счетчик ссылок для обеих областей памяти уменьшается до 1

  3. , а anakin сбрасывается, в результате чего объект R c anakin и anakin.child сбрасываются, что приводит к тому, что счетчик ссылок для обеих областей памяти становится равным go до 0.

Это где данные кучи должны быть очищены? Не удаляются ли члены объекта при его отбрасывании?

Когда я удаляю или комментирую строки, соединяющие Люка и Анакина с помощью loan_mut, удаление происходит, как и ожидалось, и сообщения выводятся правильно.

1 Ответ

1 голос
/ 13 апреля 2020
luke выходит из области видимости, что означает, что его члены, которыми он владеет, также исключаются. Так что Люк и Люк. Родитель, брось. Оба являются Rcs, поэтому счетчик ссылок для обеих областей памяти уменьшается до 1

Это шаг, где вы неправильно понимаете.

Не сбрасываются ли члены объекта при его отбрасывании?

Точно. Количество, которое уменьшается, напрямую связано с данными, которые указывает R c. Когда luke выходит из области видимости, Rc выходит из области видимости, и количество элементов, ссылающихся на RefCell luke, уменьшается, код ничего не знает о luke.parent.

В Ваш код, после

luke.borrow_mut().parent = Some(anakin.clone());
anakin.borrow_mut().child = Some(luke.clone());

имеется 4 Rc объектов (2 в стеке, 2 в куче) и 2 RefCell объектов в куче с подсчетами, связанными с ними. Каждый RefCell имеет счет 2, как вы видели, потому что 2 Rc s ссылаются на каждый RefCell.

Когда anakin падает, счет для его RefCell уменьшается, поэтому у вас есть luke RefCell в куче со счетом 2 и anakin RefCell со счетом 1.

Когда luke падает затем уменьшается число , RefCell, поэтому каждый из них теперь имеет счет 1. В итоге в стеке не останется значений Rc, которые ссылаются на RefCell, но каждый RefCell ссылается на other RefCell, поэтому у Rust нет способа узнать, что они безопасны быть исключенным.

Не могу точно сказать по вашему вопросу, но это абсолютно ожидаемое ограничение типа Rc при использовании с RefCell, поскольку оно позволяет вводить циклы в собственность объекты.

Ваш код является почти минимальным воспроизводимым примером цикла R c: Что является минимальным примером цикла зависимости R c?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...