Каким образом в Rust осуществляется управление памятью при чтении данных?

Почему функция `file.read().unwrap().read_at(info.1, &mut buf).expect` приводит к утечке памяти после множества вызовов?
  • 9 февраля 2024 г. 16:39
Ответы на вопрос 2
В Rust управление памятью осуществляется через систему владения (ownership), заимствования (borrowing) и жизненных циклов (lifetimes). Каждое значение в Rust имеет своего "владельца", и только владелец мо¬жет менять это значение. Механизм заимствования позволяет ссылаться на данные, не забирая владение. Rust проверяет соблюдение этих правил во время компиляции, что не только предотвращает утечки памяти и гонки данных, но и гарантирует безопасность работы с памятью.

Однако, ошибка в управлении памятью все равно может происходить в случаях использования неустойчивых (unsafe) операций, неправильного использования `std::mem::forget`, утечек внутри сторонних библиотек, циклических ссылок во время использования `Rc` и `Weak`, или некорректного управления ресурсами операционной системы, например при работе с файлами.

Судя по предоставленному вами коду:

```rust
file.read().unwrap().read_at(info.1, &mut buf).expect(...)
```

Он является пограничным случаем, и невозможно точно определить проблему без контекста. Однако, можно сформулировать некоторые предположения относительно утечек памяти:

1. Если `file.read()` возвращает значение, которое должно быть освобождено, но не освобождается, то это может привести к утечке памяти.

2. Если метод `read_at()` внутренне выделяет память, которая должна быть освобождена, но не освобождается при вызове метода, это тоже может привести к утечке памяти.

3. Если `info` или `buf` содержат типы, требующие явного освобождения ресурсов (например, через вызов специального метода или обернуты во что-то типа `CString`), и они не управляются должным образом, то это также может вызвать утечку памяти.

4. В Rust есть встроенные механизмы для предотвращения утечек памяти, такие как автоматический вызов деструкторов у объектов при выходе из области видимости. Если код неправильно пользуется этими механизмами, возможно возникновение утечки.

5. Использование `unwrap()` и `expect()` может привести к панике и некорректному завершению программы, если результат содержит ошибку, но это не должно приводить к утечке памяти, если только в панике не участвуют неустойчивые (unsafe) блоки или внешние ресурсы.

Для более точных выводов необходимо исследовать конкретные реализации `read()` и `read_at()` методов и контекст, в котором они используются. Общий совет — необходимо следить за тем, чтобы все ресурсы были корректно освобождены, и проверять, не возникают ли утечки памяти из-за неправильного управления ресурсами операционной системы или сторонних библиотек.
TL;DR; 10400000 * 100 - это как раз почти гигабайт. 
В текущем виде это компилироваться не должно, тк as_slice возвращает ссылку, а чтобы структура могла содержать в себе ссылку - нужно добавить лайфтайм в объявление структуры => этот же лайфтайм нужно будет указать в сигнатуре функции.
Сейчас ни того ни другого я не вижу и код не должен компилироваться по причине того что ты пытаешься вернуть ссылку на данные, которые живут только в рамках fn get.
Если же BinValue на самом деле владеет вектором, то это не утечка, а вполне ожидаемое поведение.
Смотри, где должен он дропаться в будущем.

1. Тут можно достаточно легко избавиться от unsafe:

Превращается в

2.
Вообще достаточно странный код.
На этой строке мы создали вектор - это ок. Он требует места в куче. Хотя странно, что info.0 у нас u64, а не usize
let mut buf = vec![0; info.0 as usize];
Тут мы файл прочитали. Возможно был смысл сделать BufRead, но не думаю, что он тут бы тут много чего сделал бы.
В остальном тут нет аллокаций.

3. А вот это уже выглядит реально подозрительно:
return Some(BinValue::new(buf.as_slice()));
Это вообще компилируется? Покажи, что из себя представляет BinValue.
По хорошему оно должно брать ownership над вектором.


Если оставить код таким, то через 10 400 000 вызовов этой функции с заполнение буфера 100-байтовыми значениями утечёт примерно 1 ГБ памяти

10 400 000 * 100 = как раз примерно гиг.
Если BinValue в действительности берёт ownership, то это вполне себе ожидаемое поведение, а не утечка.

4. Ещё я бы на всякий случай убрал #[inline(always)]
Похожие вопросы