LINUX.ORG.RU

Вопрос по ручному управлению памятью

 ,


1

2

Я в этом не разбираюсь, но возник такой вопрос. Считается, что в языках с GC нет ручного управления, а, например в сишке есть.

Меня заинтересовал вот какой вопрос. Допустим, мы пишем команду «освободить память такую-то». Интересно, что реально тут происходит в этот момент? Исполнение останавливается до тех пор, пока память не будет освобождена, а затем возобновляется? В таком случае, у нас разница между языком с GC и без него только в том, что нет накладных расходов на сам GC, на алгоритмы подсчета ссылок и/или обход дерева. Непосредственно на расход памяти это не влияет, практически, так получается?

И, кстати, что представляет из себя процесс освобождения памяти, на более низком уровне?

ЗЫ пришлось поставить тег c++, поскольку тегов связанных с «просто си» не нашел вообще. Подскажите что поставить по си.



Последнее исправление: cetjs2 (всего исправлений: 2)
Ответ на: комментарий от forCe

Я бы сказал в языке без возможностей выбора технологии управления памятью.

Ну хорошо, в C++ есть выбор такой технологии и вы считаете, что в C++ есть автоматическое управление памятью. Например, вот в таком примере:

A * p;
{
    auto a = make_unique<A>(10, "aaa", 20.2);
    a->foo(10);
    a->bar("asaaa");
    p = a.get(); 
}
p->bar("bang!");
Где будет это самое автоматическое управление?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

В спп есть понятие автоматической памяти. В стандарте, да. Почитай, откроешь для себя много нового.

anonymous
()
Ответ на: комментарий от anonymous

Давайте сразу цитату. А то ведь вы могли читать книгу, а увидеть не пойми что.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Ну хорошо, в C++ есть выбор такой технологии

Он там шире.

в C++ есть автоматическое управление памятью

Полуавтоматическое=) Причем полуавтоматическое управление ресурсами индифферентно к виду ресурса. Память, файлы, соединения, блокировки и пр. - со всем работаем в едином стиле. Полностью автоматические системы пока приемлемо управляют только памятью.

Где будет это самое автоматическое управление?

Полуавтоматическое. Владельцем ресурса является a, после его уничтожения он освободит ресурс. А баги - это баги. Если я стану использовать boehm gc, то смогу так же испортить себе жизнь, правда чуть сместить указатель нужно будет. Так что вид управления памятью тут ортогонален наличию подобных ошибок. Тут все зависит от языка.

forCe
()
Ответ на: комментарий от forCe

Причем полуавтоматическое управление ресурсами индифферентно к виду ресурса.

Речь идет не о том, что механизм RAII в C++ успешно используется для управления разными типами ресурсов, включая динамическую память. А о том, что даже при этом всем управление динамической памятью все равно в C++ осуществляется вручную. В отличии от языков с GC.

А баги - это баги.

Только вот в языках с GC здесь не будет такого злобного бага, как в C++.

Другое дело, что в языках с GC есть свои заморочки, начиная от зануления ссылок на ненужные объекты в долгоживущих структурах данных и заканчивая работой GC только с памятью (за бортом оказываются другие типы ресурсов, вроде файловых хендлов). Но это тема отдельного разговора.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

А о том, что даже при этом всем управление динамической памятью все равно в C++ осуществляется вручную.

Не вручную. Я нигде не пишу операции освобождения, я не пытаюсь рассмотреть все ветви исполнения и смотреть, не будет ли у меня утечки ресурса, я не просматриваю каждый return/throw на предмет корректного выхода, я не пытаюсь вставить костыли в духе finally(java до 7) или goto к коду освобождения ресурсов(C) и пр. и пр.

RAII и RC относятся к полуавтоматическому управлению памятью. Отдельного класса управления эти механизмы заслуживают хотя бы потому, что отличаются как от ручного управления, так и от GC достаточно существенно.

В отличии от языков с GC

в языках с GC

в языках с GC

Я бы все таки отделял способ управления памятью от языка. По мне так полноценный язык должен позволять использовать как минимум два(полуавтоматическое и автоматическое).

forCe
()
Ответ на: комментарий от forCe

RAII и RC относятся к полуавтоматическому управлению памятью.

Возможно, кому-то так удобно считать. Но здесь подменяется смысл. RAII и RC отвечают за освобождение памяти. А это только часть проблемы управления ею.

Выше уже был продемонстрирован пример с сохранением во внешней переменной указателя из unique_ptr. RAII обеспечило удаление объекта. Но никак не справилось с появлением повисшего указателя.

И не могло справится.

Поэтому-то ваши с i-rinat взгляды на роль RAII меня и не убеждают. Как было в C++ ручное управление, так и осталось. Хорошо хоть, что упростилось за счет включенных в стандарт средств.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Выше уже был продемонстрирован пример с сохранением во внешней переменной указателя из unique_ptr. RAII обеспечило удаление объекта. Но никак не справилось с появлением повисшего указателя.

Это не имеет отношения к GC. Это демонстрация свойств языка. Я же говорил вам про boehm gc, а вы проигнорировали. Тоже касается и C++/CLI упомянутого выше.

Rust, например, без GC справляется с подобными ошибками.

И не могло справится.

А в Rust справляется :)

А GC может не справиться(например, в С) =) Вы, на мой взгляд, путаете особенности языка и особенности GC.

forCe
()
Последнее исправление: forCe (всего исправлений: 1)
Ответ на: комментарий от forCe

Это не имеет отношения к GC. Это демонстрация свойств языка. Я же говорил вам про boehm gc, а вы проигнорировали.

Имеет и самое непосредственное. Нормальный GC решает проблемы не только с освобождением памяти, но и с отсутствие таких вещей, как повисшие указатели, повторное освобождение памяти и пр. проблемные места языков с ручным управлением памятью.

Про boehm gc смысла разговаривать нет, поскольку он не является частью стандарта C++ (в отличии от unique_ptr/shared_ptr). Подключение boehm gc в С++ программу полностью аналогично написанию каких-то своих, заточенных под конкретную задачу инструментов для управления памяти. Под конкретную задачу и конкретный компилятор можно вообще точный GC реализовать. Но это вовсе не будет означать, что из C++ исчезло ручное управление памятью.

Rust, например, без GC справляется с подобными ошибками.

Rust, как и упомянутый выше C++/CLI, не является доказательством тезиса i-rinat о том, что из C++ почти исчезло ручное управление памятью. А именно отсутствие каких-либо внятных обоснований этого тезиса и определяет мое участие в данном споре.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Нормальный GC решает проблемы не только с освобождением памяти, но и с отсутствие таких вещей, как повисшие указатели, повторное освобождение памяти и пр.

Хм. Давайте рассмотрим, каким образом GC это делает? Я вот считаю, что GC такими вещами не занимается, а перечисленные гарантии дает язык.

forCe
()
Ответ на: комментарий от eao197

проблемные места языков с ручным управлением памятью.

Но ведь Rust, который не имеет GC и не заточен под него, таких проблем не имеет.

из C++ исчезло ручное управление памятью.

из C++ почти исчезло ручное управление памятью. А именно отсутствие каких-либо внятных обоснований этого тезиса и определяет мое участие в данном споре.

Но вы ведь помимо оспаривания этого тезиса много чего наговорили=) И мое участие обусловлено несогласием с некоторыми вашими высказываниями.

forCe
()
Ответ на: комментарий от forCe

Хм. Давайте рассмотрим, каким образом GC это делает? Я вот считаю, что GC такими вещами не занимается, а перечисленные гарантии дает язык.

Имхо, при проектировании языка его авторы отталкиваются от наличия или отсутствия GC. При наличии GC появление повисших указателей затруднительно просто потому, что если есть живой ненулевой указатель, то объект, на который он указывает, так же будет считаться живым и не будет собран GC. Отсюда исчезновение проблемы повисших указателей как класса. Так же как класс исчезают проблемы с повторным освобождением памяти, т.к. память вручную не освобождается.

Так же языки с GC вынуждены проводить жесткое различие между ссылочными типами и типами-значениями. Так, скорее всего в языке с GC будет существовать запрет на взятие ссылки на экземпляр типа-значения. Т.е. нельзя будет взять ссылку на примитивный int, а потребуется обернуть его в какой-то ссылочный тип и брать ссылку уже на экземпляр обертки (емнип, это называется boxing/unboxing). Следствием чего является отсутствие такой штуки, как (временные) автоматические экземпляры ссылочных типов. Поэтому нет такой проблемы, как возврат ссылки на временный экземпляр, удаляющийся при выходе из области видимости.

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

Возможно, где-то есть языки, которые пытаются играть сразу на двух площадках (вроде D, где предпринимаются попытки отвязать рантайм и std-lib от GC). Но так уж получается, что все, что успешно доказало свою жизнеспособность и применимость в широком классе задач либо живет только с GC, либо без GC.

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

Но ведь Rust, который не имеет GC и не заточен под него, таких проблем не имеет.

Во-первых, Rust я не знаю в достаточной степени, чтобы всерьез о нем говорить.

Во-вторых, в языке Rust были сделаны определенные вещи, дабы контролировать действия пользователя, которых нет в C++. Так что уже в этом плане Rust пошел в сторону автоматизированного контроля за управлением памятью дальше, чем C++.

В-третьих, про успешность Rust-а в реальных разработках, имхо, судить преждевременно. Не исключено, что в больших проектах и больших командах обнаружатся фатальные недостатки в Rust-е. Которые либо приведут к внесению изменений в язык, либо же к чрезмерному использованию его unsafe-возможностей.

И мое участие обусловлено несогласием с некоторыми вашими высказываниями.

Я старался всего лишь аргументировать свою точку зрения на то, почему в C++ ручное управление памятью. Не нужно мои высказывания проектировать на проблемы GC/не-GC вообще. Для такого обширного разговора я некомпетентен и не смогу его продолжать.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

при проектировании языка его авторы отталкиваются от наличия или отсутствия GC

Для начала они думают, нужен им GC или нет. Причем если они еще до того решили делать язык безопасным с точки зрения управления памятью, то GC будет для них хорошим и адекватным выбором. По крайней мере так было раньше. Rust, например, пошел другим путем.

При наличии GC появление повисших указателей затруднительно просто потому, что если есть живой ненулевой указатель, то объект, на который он указывает, так же будет считаться живым и не будет собран GC

Это зависит от многих условий. Можно сделать так, что не будет считаться. Можно вводить отдельные типы для передачи ссылки из кучи в нативные вызовы. Вроде того же pin_ptr. Разные могут быть решения с разными последствиями=)

Отсюда исчезновение проблемы повисших указателей как класса.

Так же как класс исчезают проблемы с повторным освобождением памяти

Это все следствие не наличия GC, а отсутствия других механизмов=) А это уже свойство языка.

Для такого обширного разговора я некомпетентен и не смогу его продолжать.

Ок. А я бы поговорил.

forCe
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.