Garbage collection vs manual memory management
От: johny5 Новая Зеландия
Дата: 08.01.15 10:01
Оценка: 22 (1) +1 -1 :)))
Сразу скажу тут скорее не то что вы ожидаете, это не очередной вброс о производительности программ написанных на C# и C++.


Меня волнует другая тема: в C# / С++ главное отличие не в том что делаешь ты явно delete или среда подчистит его для тебя.
А главное тут в том что ты можешь сделать delete когда тебе угодно, а в C# нет.

Общались с Джавистом пересевшим на С++. Мол висящие указатели, явная чистка памяти, и т.д. Всё это плохо и известно. Он предлагает универсальное решение — shared_ptr на всё. Я задал контрольный вопрос: есть кнопка, к ней привязан звук из менеджера звуков. Мы решили перегрузить менеджер звуков. Нам для этого старый нужно удалить а в новом все звуки загрузить заново. И что я слышу от него, оказывается это нормально в данном случае что кнопка на UI не даст старому звуковому менеджеру умереть!! А если там нужно драйвер переиниализировать, старый обязательно должен выгрузить своё.

Я до сих пор в шоке. Это ужос для С++ профессионала, вдруг оказаться в языке где ты не можешь контролировать жизнь объектов вокруг тебя.

Я сам С++ник и безуспешно пытался пересесть на С#. Я поимел реальных проблем с тем что я впринципе не имею никакого контроля над временем жизни объектов мной созданных. К примеру загрузил я файл в модель, отобразил модель на форму и всё, хочу удалить и загрузить новую модель, но я не могу потому что в языке просто нет таких средств. Всё что тут можно сделать это подчистить везде везде везде ссылки на эту форму, на модель и скрестить пальцы что скоро всё само удалится. И всё равно не срабатывает в 50% случаях.

Вопрос к вам ко всем, каков стиль программирования должен быть чтобы можно было бы писать в GC языках. Как добиваться модульности, ООП, когда не всё тянет всё, а модуль сам за себя и свои части отвечает. И, в частности, как вы делаете загрузку выгрузку данных модели, ведь от старых данных так просто не избавишься даже если ты скажешь Clear() всем контейнерам.
Re: Garbage collection vs manual memory management
От: s_aa Россия  
Дата: 08.01.15 10:27
Оценка: +1
>отобразил модель на форму и всё, хочу удалить и загрузить новую модель, но я не могу потому что в языке просто нет таких средств.

Ну и загружай новую, старая подчистится GC если ссылок нет, зачем удалять, забыл про нее и все.
Жизнь не обязана доставлять удовольствие. Достаточно отсутствия страданий.
Re[2]: Garbage collection vs manual memory management
От: johny5 Новая Зеландия
Дата: 08.01.15 10:46
Оценка:
Здравствуйте, s_aa, Вы писали:

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


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


А если есть то не подчистится. А ссылки могут быть где угодно, в подписках на евенты, в кэше дот нета, нечаянно скаптурил this в какой то мелкой лямбде... И это лямбда потянет за собой ВСЁ.

Я об этом и говорю что тут токо сиди и надейся что оно сработает, нет в языке средств прямого управления временем жизни объекта.
Re[3]: Garbage collection vs manual memory management
От: Tissot Россия  
Дата: 08.01.15 11:07
Оценка: +3
Здравствуйте, johny5, Вы писали:

J>А если есть то не подчистится. А ссылки могут быть где угодно, в подписках на евенты, в кэше дот нета, нечаянно скаптурил this в какой то мелкой лямбде... И это лямбда потянет за собой ВСЁ.


Не могли бы вы расписать, как тут может помочь ручное управление памятью?
Елси вы просто вызовете delete для нужного объекта, те, кто все еще имеет ссылки на него, будут продолжать держать ссылку на уже освобожденный объект, что гораздо хуже.
Re[3]: Garbage collection vs manual memory management
От: Sergey J. A. Беларусь  
Дата: 08.01.15 11:07
Оценка: +6
J>А если есть то не подчистится. А ссылки могут быть где угодно, в подписках на евенты, в кэше дот нета, нечаянно скаптурил this в какой то мелкой лямбде... И это лямбда потянет за собой ВСЁ.

J>Я об этом и говорю что тут токо сиди и надейся что оно сработает, нет в языке средств прямого управления временем жизни объекта.


А в плюсах что будет? Указатель на мусор?
Re: Garbage collection vs manual memory management
От: vsb Казахстан  
Дата: 08.01.15 11:33
Оценка: +10
Если у тебя бардак в программе и ты не знаешь, кто куда указывает, то это бардак, а не недостатки GC. Причём даже в твоём use-case GC выигрывает. В самом худшем случае ты получишь утечку памяти. Что ты получишь в C++ – вообще никто не знает, в лучше случае падение.
Re: Garbage collection vs manual memory management
От: AlexRK  
Дата: 08.01.15 13:19
Оценка: +1
Здравствуйте, johny5, Вы писали:

J>Вопрос к вам ко всем, каков стиль программирования должен быть чтобы можно было бы писать в GC языках. Как добиваться модульности, ООП, когда не всё тянет всё, а модуль сам за себя и свои части отвечает. И, в частности, как вы делаете загрузку выгрузку данных модели, ведь от старых данных так просто не избавишься даже если ты скажешь Clear() всем контейнерам.


Ну так в C/С++ вы получите крах программы (в лучшем случае), если насильственно удалите то, что где-то используется.

Мне больше всего нравится подход Rust — ни сборки мусора, ни опасного удаления вручную.
Re: Garbage collection vs manual memory management
От: Васильич  
Дата: 08.01.15 13:27
Оценка: +4 -1
Здравствуйте, johny5, Вы писали:

J>Меня волнует другая тема: в C# / С++ главное отличие не в том что делаешь ты явно delete или среда подчистит его для тебя.

J>А главное тут в том что ты можешь сделать delete когда тебе угодно, а в C# нет.

Мне кажется, тут налицо попытка идти в чужой монастырь со своим уставом. Фундаментально нет большой разницы между C++ и C#: в последнем случае менеджер памяти умеет автоматически освобождать неиспользуемую более память, но не более того. Очень утрированно можно считать, что "v = null" в C# эквивалентно "delete(v)" в C++, с той разницей, что в последнем случае память будет освобождена немедленно, а в первом — когда-нибудь в будущем.

В обоих случаях программист обязан:
1. Явно закрывать неиспользуемые более ресурсы (файлы, коннекшены к БД, и т.д.)
2. Явно обнулять все дополнительные ссылки на удаляемый объект.

Возьмем ваш пример с кнопкой и прикрепленным к ней звуком. В C++ никто не отменяет обязанность присвоить кнопке новый указатель на звук после рестарта менеджера звуков, соответственно у вас будет некий алгоритм по уведомлению подписанных объектов о рестарте менеджера. Абсолютно то же самое будет в C#. Никаких проблем с зависшими объектами не возникнет.
Re: Garbage collection vs manual memory management
От: Abyx Россия  
Дата: 08.01.15 13:31
Оценка: +2
Здравствуйте, johny5, Вы писали:

J>А главное тут в том что ты можешь сделать delete когда тебе угодно, а в C# нет.


J>Общались с Джавистом пересевшим на С++. Мол висящие указатели, явная чистка памяти, и т.д. Всё это плохо и известно. Он предлагает универсальное решение — shared_ptr на всё. Я задал контрольный вопрос: есть кнопка, к ней привязан звук из менеджера звуков. Мы решили перегрузить менеджер звуков. Нам для этого старый нужно удалить а в новом все звуки загрузить заново. И что я слышу от него, оказывается это нормально в данном случае что кнопка на UI не даст старому звуковому менеджеру умереть!! А если там нужно драйвер переиниализировать, старый обязательно должен выгрузить своё.


Джавист в чем-то прав. Надо использовать shared_ptr и weak_ptr. У кнопки был бы weak_ptr и она не мешала бы удалить менеджер звуков.

Что касается C# — никто не мешает тебе сделать weak_ptr в C#. Просто там никто так не делает, слишком неудобно/сложно.
In Zen We Trust
Re: Garbage collection vs manual memory management
От: Jack128  
Дата: 08.01.15 13:46
Оценка: +2
Здравствуйте, johny5, Вы писали:

В описанной ситуации в плюсах мы получим битый указатель, а шарпе мемлик, это понятно.
Меня вот какой вопрос больше интересует. В плюсах при использовании какого нить отладочного манагера памяти при нажатии на кнопку, ссылающуюся на убитый менеджер звуков, мы практически гарантированно AV получим и начнем править багу. А вот в .NET обработчик нормально отработает, ошибка будет логическая и возможно плохо заметная. Как с этим бороться ?
Re[2]: Garbage collection vs manual memory management
От: Alex912  
Дата: 08.01.15 14:10
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Что касается C# — никто не мешает тебе сделать weak_ptr в C#. Просто там никто так не делает, слишком неудобно/сложно.


Это что-то типо здесь ?
Re[3]: Garbage collection vs manual memory management
От: Abyx Россия  
Дата: 08.01.15 15:58
Оценка:
Здравствуйте, Alex912, Вы писали:

A>Здравствуйте, Abyx, Вы писали:


A>>Что касается C# — никто не мешает тебе сделать weak_ptr в C#. Просто там никто так не делает, слишком неудобно/сложно.


A>Это что-то типо здесь ?


да
In Zen We Trust
Re: Garbage collection vs manual memory management
От: Abyx Россия  
Дата: 08.01.15 16:08
Оценка:
Здравствуйте, johny5, Вы писали:


J>Сразу скажу тут скорее не то что вы ожидаете, это не очередной вброс о производительности программ написанных на C# и C++.

J>

J>Меня волнует другая тема: в C# / С++ главное отличие не в том что делаешь ты явно delete или среда подчистит его для тебя.

J>А главное тут в том что ты можешь сделать delete когда тебе угодно, а в C# нет.

вообще тут проблема исключительно архитектурная.
в С# тоже можно сделать "delete". Если ты знаешь что на объект есть только одна ссылка, то присвоив ей null ты почти сразу же удалишь этот объект.
так что можно добавить дополнительную косвенность, и вместо самого объекта отдавать обертку со ссылкой на него.
In Zen We Trust
Re[2]: Garbage collection vs manual memory management
От: denisko http://sdeniskos.blogspot.com/
Дата: 08.01.15 16:43
Оценка:
Здравствуйте, Abyx, Вы писали:

A>Здравствуйте, johny5, Вы писали:



J>>Сразу скажу тут скорее не то что вы ожидаете, это не очередной вброс о производительности программ написанных на C# и C++.

J>>

J>>Меня волнует другая тема: в C# / С++ главное отличие не в том что делаешь ты явно delete или среда подчистит его для тебя.

J>>А главное тут в том что ты можешь сделать delete когда тебе угодно, а в C# нет.

A>вообще тут проблема исключительно архитектурная.

A>в С# тоже можно сделать "delete". Если ты знаешь что на объект есть только одна ссылка, то присвоив ей null ты почти сразу же удалишь этот объект.
Это тоже мягко говоря не совсем так http://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx
<Подпись удалена модератором>
Re: IDisposable спасет отца русской демократии (-)
От: 0x7be СССР  
Дата: 08.01.15 18:53
Оценка:
Re[4]: Garbage collection vs manual memory management
От: johny5 Новая Зеландия
Дата: 08.01.15 20:36
Оценка: :)
Здравствуйте, Sergey J. A., Вы писали:

J>>А если есть то не подчистится. А ссылки могут быть где угодно, в подписках на евенты, в кэше дот нета, нечаянно скаптурил this в какой то мелкой лямбде... И это лямбда потянет за собой ВСЁ.


J>>Я об этом и говорю что тут токо сиди и надейся что оно сработает, нет в языке средств прямого управления временем жизни объекта.


SJA>А в плюсах что будет? Указатель на мусор?


Как то не возникает с этим проблемы в C++, не все мусорные указатели на самом деле используются. Кроме того, в С++ есть возможность передаваемую структуру данных скопировать by value. В С# это не подрузамевается но если сильно надо то конечно можно, только какой смысл тогда кодить на C# если там так всё сложно и ты должен думать над передачей каждого указателя и каждой лямбдой. Ничего GC тогда не облегчает а даже наоборот. Кроме того мемори лики оочень сложно искать, я потратил неделю. В случае с С++ висячий указатель выстрелил бы почти сразу.
Re[2]: Garbage collection vs manual memory management
От: johny5 Новая Зеландия
Дата: 08.01.15 20:48
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>В самом худшем случае ты получишь утечку памяти.


Как раз C# приложение будет крошиться, потому что та модель которая должна бы уже умереть, всё ещё живая а значит есть какие то нити её подпитывающие. В частности подписки на UI контролы, с коими я боролся. Там нет возможности отписаться никак, а weak subscription работает ровно столько насколько ты уверен что твой объект таки умрёт.

Мне же приходилось скакать через весь код сканировать что где я подписался неправильно. В С++ модульности такое просто невозможно, каждый модуль независим. Проблема с dangling pointers в С++ есть, но обычно если модуль 1 знает что модуль 2 отключен то все такие указатели уже просто не используются. Тут нужна просто более грамотная модульная организация, но всё таки в С++ можно сказать что ООП тут работает в полную силу а в С# один спагетти код, где всё всё тянет за ручку.

Вообще это форум философии а не священных воин. Я хочу понять как другие люди кодят на C#, избегая подобных проблем. Стиль кодирования, как я тут где то читал, на C# и C++ разнится кардинально, я бы с удовольствием почитал бы как именно. С++ подход в С#, как видно, проваливается в полный рост.
Re[2]: Пара примеров
От: johny5 Новая Зеландия
Дата: 08.01.15 22:12
Оценка:
Здравствуйте, Васильич, Вы писали:

В>В обоих случаях программист обязан:

В>1. Явно закрывать неиспользуемые более ресурсы (файлы, коннекшены к БД, и т.д.)
В>2. Явно обнулять все дополнительные ссылки на удаляемый объект.

П.2 в С++ не обязателен, смотрите ниже.


В>Возьмем ваш пример с кнопкой и прикрепленным к ней звуком. В C++ никто не отменяет обязанность присвоить кнопке новый указатель на звук после рестарта менеджера звуков, соответственно у вас будет некий алгоритм по уведомлению подписанных объектов о рестарте менеджера. Абсолютно то же самое будет в C#. Никаких проблем с зависшими объектами не возникнет.


Да, тут вы правы, на самом деле в C++ для таких мало связанных систем мы бы тоже использовали какие то хэндлы. Сам хэндл правда мог бы и содержать указатель но в С# нельзя, только если это weak_ptr<> но я так понял в С# его так широко не используют.

<rant on>
Уф.. Это ж какое то наказание, за то что GC собирает для вас память вы теперь должны скурпулёзно подсчитывать ссылки для него, чтоб не дай бог где чего.
<rant off>

Окей, пара практических примеров.


Модульность


Модуль 1 подключается к Модулю 2.
Идёт обмен данными.
Модуль 2 кем то явно убивается.
Модуль 1 пытается опять подключиться к модулю 2.
Обмен данных не инициируется.

В С++ эта модульность — спасительный круг в мире висящих указателей, определённый функционал просто не будет запущен если какое то условие на более высоком уровне не было выдержано. В данном случае какой то блок внутри Модуля 1 будет просто отключен и что какие ссылки и структуры он содержит и куда оно всё ссылается оно всё становится неважно. По сути это приводит к повышению требования к качеству ООП в С++.

В C# же, модуль 2 всегда должен знать где как и кому он отдался, и возможно на Finalize сам должен уметь себя подчищать, .. и по моему небольшому опыту
Автор: johny5
Дата: 16.01.14
некоторые из этих случаев достаточно нетривиальны.

-------------------------


Копирование по значению


Тут я пытался придумать как копирование по значению в С++, поможет в данной проблеме но не нашёлся что написать... т.к. копирование, в общем случае, вызовет копирование всех ссылок внутри.
Re: Garbage collection vs manual memory management
От: c-smile Канада http://terrainformatica.com
Дата: 08.01.15 22:14
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:

На самом деле проблема конечно есть.

UI код характризуется достаточно сложными ownership graphs когда сложно установить кто чем владеет.
То же самое про асинхронный код где promise promise'ом погоняет.

Т.е. GC в UI скорее благо чем зло.

Идеальная среда/язык это нечто позволяющее декларирвать domains — вот manageable (GCable) domain/namespace, а вот deterministic domain.

Я был питал надежды на D language в этом смысле. Там в принципе можно руками писать delete когда нужно.
Но это к сожалению не отменяет глобальный и весьма консервативный GC.

В результате пришел к Sciter в котором code behind UI пишется на JavaScript alike языке с четко очерченным managed <-> native gateway.
То что называется business logic удобно, эффективно и детерминировано пишется на C/C++. UI же декларатинвный и managed.
Это в принципе близко, но не 100% идеально конечно.

Что-то типа @autoreleasepool {} areas из ObjC, но не так прямолинейно...

А воообще тема интересная. Вангую что языкостроение будет развиваться в эту сторону тоже в боижайшее время.
Re: Garbage collection vs manual memory management
От: __kot2  
Дата: 08.01.15 22:17
Оценка:
Здравствуйте, johny5, Вы писали:
J>Я сам С++ник и безуспешно пытался пересесть на С#. Я поимел реальных проблем с тем что я впринципе не имею никакого контроля над временем жизни объектов мной созданных. К примеру загрузил я файл в модель, отобразил модель на форму и всё, хочу удалить и загрузить новую модель, но я не могу потому что в языке просто нет таких средств. Всё что тут можно сделать это подчистить везде везде везде ссылки на эту форму, на модель и скрестить пальцы что скоро всё само удалится. И всё равно не срабатывает в 50% случаях.
да, есть такой прикол — вместо delete приходится вызывать dispose. поэтому грамотная работа с памятью в C#, Java становится ничем не проще С++

собственно, я только потому питоном и пользуюсь, что там reference counting а не дурацкий непонятно как работающий GC
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.