Comments 77
Не уж-то так плохо написал?
0
Ну почему же. Просто материал довольно заезженный (все читали в том или ином виде), к тому же… ну не то что бесполезный, но как-то перспективы не очень ясны — зачем вообще собственноручно управлять сборкой мусора ( не «как», а именно зачем).
На мой взгляд это вредно, потому как простые примеры, которыми обычно иллюстируют описание «как» — в реальности не требуют такого управления, а вручную управлять памятью в сложных системах — это как всунуть гвоздь в цилиндр работающего двигателя внутреннего сгорания — теоретически наверно возможно, но нужно чертовски хорошо понимать — что именно и зачем делается.
GC и создавался специально для того, чтобы программисты больше не занимались управлением памятью, а тут можно сказать — рецидив прям.
Лучше переведите вот эту
статью (и там были сопутствующие вроде), заодно расскажете всем — почему вручную управлять памятью в .NET можно но не нужно =).
На мой взгляд это вредно, потому как простые примеры, которыми обычно иллюстируют описание «как» — в реальности не требуют такого управления, а вручную управлять памятью в сложных системах — это как всунуть гвоздь в цилиндр работающего двигателя внутреннего сгорания — теоретически наверно возможно, но нужно чертовски хорошо понимать — что именно и зачем делается.
GC и создавался специально для того, чтобы программисты больше не занимались управлением памятью, а тут можно сказать — рецидив прям.
Лучше переведите вот эту
статью (и там были сопутствующие вроде), заодно расскажете всем — почему вручную управлять памятью в .NET можно но не нужно =).
+5
Просто у меня было пара знакомых программистов, которые постоянно с этим работали с низкоуровневым программированием на C#. Чуть ли не CIL-коды прописывали.
> Лучше переведите вот эту
статью (и там были сопутствующие вроде), заодно расскажете всем — почему вручную управлять памятью в .NET можно но не нужно =)
Я это могу рассказать и без всякой статьи)
> Лучше переведите вот эту
статью (и там были сопутствующие вроде), заодно расскажете всем — почему вручную управлять памятью в .NET можно но не нужно =)
Я это могу рассказать и без всякой статьи)
0
Могу ответить зачем. Затем что GC убирает мусор, но не обязан выполнять это сразу после выхода из области видимости. И неоднократно сталкивался в реальных приложениях, обрабатывающих большие массивы данных (сотни тысяч изображений, например), когда приложение начинает занимать по полгига и больше оперативы. Со сбором же памяти с использованием следующей функции объем занимаемой памяти не поднимался выше 10 мегабайт. Так что все зависит от задачи.
[DllImport("kernel32.dll")]
private static extern bool SetProcessWorkingSetSize(IntPtr handle, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void Collect()
{
GC.Collect();
GC.WaitForPendingFinalizers();
SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}
0
Это аналог вызова EmptyWorkingSet. Он не освобождает память. Просто урезает private working set — значение, которое по умолчанию показывает task manager.
Естественно, последующий своп и тормоза при этом обеспечены. Иметь на среднем десктопе 4Gb памяти, и при этом принудительно заставлять приложение свопить и не выходить за пределы 10 мегабайт — преступление.
Посмотрите статью habrahabr.ru/blogs/windows/107605/ — там в разделе task manager есть даже скрипт для «оптимизации всего подряд», вместе с обоснованием «полезности» такой «оптимизации».
Естественно, последующий своп и тормоза при этом обеспечены. Иметь на среднем десктопе 4Gb памяти, и при этом принудительно заставлять приложение свопить и не выходить за пределы 10 мегабайт — преступление.
Посмотрите статью habrahabr.ru/blogs/windows/107605/ — там в разделе task manager есть даже скрипт для «оптимизации всего подряд», вместе с обоснованием «полезности» такой «оптимизации».
+3
Это задача была для машины где 512 мегабайт оперативы и до 150 параллельно исполняющихся задач. Но конечно я с вами согласен. В общем случае можно доверить сборщику. Но все таки бывает необходимость и в ручном вызове.
0
Необходимость в ручном вызове естественно бывает, иначе возможности его сделать просто не было бы. Но в таких жестких условиях просто вызова GC — мало. Нужно полноценное ужимание приложения — ngen для шаринга native images, MemoryFailPoint-ы, и полное понимание всех деталей работы GC. К сожалению, обычно ручная сброка мусора используется «на всякий случай».
0
«Сотни тысяч изображений» — а реализация IDisposable для изображения или для группы — никак?
Просто почему-то считается, что если уж управлять памятью — так через GC.Collect, все остальное — ниже достоинства программиста. Корректно реализовывать unmanaged взаимодействие — фи, пусть все делает фреймворк, а мы его принудительно попихаем за самую важную кнопку. А вы случайно при запросах SQL планы не подсказываете планировщику? А то 10 лет оптимизаций — не пошли ему на пользу, а вот ручное управление — наш выбор…
Просто почему-то считается, что если уж управлять памятью — так через GC.Collect, все остальное — ниже достоинства программиста. Корректно реализовывать unmanaged взаимодействие — фи, пусть все делает фреймворк, а мы его принудительно попихаем за самую важную кнопку. А вы случайно при запросах SQL планы не подсказываете планировщику? А то 10 лет оптимизаций — не пошли ему на пользу, а вот ручное управление — наш выбор…
0
IDisposable.Dispose() не освобождает память, и вообще не имеет отношения к управлению памятью. Он освобождает остальные ресурсы, а память так и остается занятой до сборки мусора.
Я иногда подсказываю планировщику запросов в SQL. FORCESEEK в моем текущем проекте местами очень помогает против дедлоков при read committed snapshot. Это плохо?
Я иногда подсказываю планировщику запросов в SQL. FORCESEEK в моем текущем проекте местами очень помогает против дедлоков при read committed snapshot. Это плохо?
+1
=) Вы разбираетесь в том, что делаете — и это замечательно.
Но, как было уже упомянуто — большинство «программистов» — непрофессионалы. И в целом распространение и популяризация текстов (а на хабре это совсем не первая серия про GC) о ручном управлении памятью в .net скорее приведет к тому, что код будет скопипащен и размножен по проектам, чем к тому, что человек возьмет Рихтера, МСДН, Чена и разберется детально в том, что именно происходит и как управлять этим механизмом не навредив .NET.
Существует достаточно других способов сделать тяжелую задачу, распараллелить ее, раньше освобождать ресурсы и убирать из области видимости тяжелые объекты, но пусть GC вызывается тогда, когда посчитает нужным CLR, а не когда посчитает нужным некоторый premature оптимизатор. В общем для 99% случаев ручная сборка не нужна, не полезна и даже вредна. Имхо.
Но, как было уже упомянуто — большинство «программистов» — непрофессионалы. И в целом распространение и популяризация текстов (а на хабре это совсем не первая серия про GC) о ручном управлении памятью в .net скорее приведет к тому, что код будет скопипащен и размножен по проектам, чем к тому, что человек возьмет Рихтера, МСДН, Чена и разберется детально в том, что именно происходит и как управлять этим механизмом не навредив .NET.
Существует достаточно других способов сделать тяжелую задачу, распараллелить ее, раньше освобождать ресурсы и убирать из области видимости тяжелые объекты, но пусть GC вызывается тогда, когда посчитает нужным CLR, а не когда посчитает нужным некоторый premature оптимизатор. В общем для 99% случаев ручная сборка не нужна, не полезна и даже вредна. Имхо.
+1
В следующей статье я расскажу, как можно собственноручно управлять процессом сборки мусора с помощью пространства имён System.GС.
Вот это поинтересней будет. Да впрочем, кому надо, тот знает, а кому надо будет, тот в мсдн полезит.
0
Все, что по этому поводу надо знать, написано у Рихтера, в CLR via C#. Зачем повторять?
+3
Причем намного более подробно, и про финализаторы, и почему чтобы убрать весь мусор нужно вызвать:
GC.Collect();
GC.WaitForPendingFinalizers();
GCCollect();
И про дефрагментацию памяти, и про Large Objects Heap, которая умеет только расти.
На самом деле тема богатая, но изложена лишь небольшая и самая очевидная часть.
GC.Collect();
GC.WaitForPendingFinalizers();
GCCollect();
И про дефрагментацию памяти, и про Large Objects Heap, которая умеет только расти.
На самом деле тема богатая, но изложена лишь небольшая и самая очевидная часть.
0
У Рихтера есть не всё, а только очень небольшая выжимка. Особенно если это 2-е издание на русском языке.
GCLatencyMode не упомянут вообще. Особенности работы с Pinned-объектами — тоже, насколько я знаю. Особенности для многоядерных систем — только вскользь, одним предложением. Для спокойной разработки Рихтера хватит. Для устранения проблем с памятью — скорее всего нет.
GCLatencyMode не упомянут вообще. Особенности работы с Pinned-объектами — тоже, насколько я знаю. Особенности для многоядерных систем — только вскользь, одним предложением. Для спокойной разработки Рихтера хватит. Для устранения проблем с памятью — скорее всего нет.
+1
Так третья редакция еще в том году вышла.
«GCLatencyMode не упомянут вообще»
Полторы страницы.
«Особенности работы с Pinned-объектами — тоже, насколько я знаю.»
Тоже, прямо скажем, страница.
«Особенности для многоядерных систем — только вскользь, одним предложением.»
Сейчас там целый раздел про треды и режимы сборки мусора.
(и отдельно еще глава про трединг вообще)
«GCLatencyMode не упомянут вообще»
Полторы страницы.
«Особенности работы с Pinned-объектами — тоже, насколько я знаю.»
Тоже, прямо скажем, страница.
«Особенности для многоядерных систем — только вскользь, одним предложением.»
Сейчас там целый раздел про треды и режимы сборки мусора.
(и отдельно еще глава про трединг вообще)
0
Третья редакция не выходила на русском. А большинство разработчиков не читает книги на английском при наличии русского перевода. Да и русский перевод многие читают наискосок — посмотрите на любых форумах на обсуждения по Dispose/Finalize — сплошные мифы и домыслы. А ведь он тоже в Рихтере расписан, в той же главе.
-1
Это говорит только о об их профессиональных данных. Таким и эта статья не поможет.
0
Некоторым достаточно статьи. Некоторым — недостаточно Рихтера.
Как ни грустно, но большинство разработчиков — непрофессионалы. Есть много студентов/джуниоров/просто не перечитывающих каждое издание Рихтера/Руссиновича/Робинса заново. Есть даже такие, что по it-тематике читают только хабр. Эта статья будет хотя бы на главной хабра, и в комментариях будет упоминаться Рихтер — уже этим она полезна.
Как ни грустно, но большинство разработчиков — непрофессионалы. Есть много студентов/джуниоров/просто не перечитывающих каждое издание Рихтера/Руссиновича/Робинса заново. Есть даже такие, что по it-тематике читают только хабр. Эта статья будет хотя бы на главной хабра, и в комментариях будет упоминаться Рихтер — уже этим она полезна.
+1
«Некоторым достаточно статьи. Некоторым — недостаточно Рихтера. „
Речь идет о том, что глупо тратить время на статью, когда есть Рихтер.
Речь идет о том, что глупо тратить время на статью, когда есть Рихтер.
0
А Вы считаете, что прямо все знаю об Рихтере?
-1
Вот эту проблему и надо решать.
«Хотите узнать о GC — прочитайте соответствующую главу в последнем Рихтере» (21-ая для третьего издания)
Зачем пересказывать ее своими словами (да еще и с ошибками)?
«Хотите узнать о GC — прочитайте соответствующую главу в последнем Рихтере» (21-ая для третьего издания)
Зачем пересказывать ее своими словами (да еще и с ошибками)?
0
Глупо тратить время на Рихтера, когда есть MSDN. Рихтер просто пересказывает его своими словами. 21-ю главу заменить парой ссылок. Проблема решена.
+1
Покажите мне ту пару ссылок, я с удовольствием их почитаю.
(ключевое условие: по ссылке должен быть последовательно изложенный текст, то есть статья о вопросе, а не референс)
(ключевое условие: по ссылке должен быть последовательно изложенный текст, то есть статья о вопросе, а не референс)
0
msdn.microsoft.com/en-us/library/0xy59wtx.aspx
Да, там надо пару раз по ссылкам пройтись. Но Рихтер с 70-ю страницами и 20+ разделами в главе тоже явно в формат статьи не впишется.
Да, там надо пару раз по ссылкам пройтись. Но Рихтер с 70-ю страницами и 20+ разделами в главе тоже явно в формат статьи не впишется.
0
Нельзя рассказать про всё и вся. Любая книга выпускается на среднего читателя. Даже с учётом узкоспециализированности какой-либо книги, есть моменты, которые нас хотелось бы видеть более глубоко, а есть те, про которые и читать особенно не хочется.
-1
Из одного слова сделать три — это надо иметь талант!
gramota.ru/slovari/dic/?word=%ED%E5+%F3%E6-%F2%EE&all=x
gramota.ru/slovari/dic/?word=%ED%E5+%F3%E6-%F2%EE&all=x
+3
Ага, читая статью, прям чувствовал что-то знакомое. А это ж вырезка из Троэлсена.
Но все равно спасибо.
Но все равно спасибо.
0
А я видел как один знакомый себе в ногу нож воткнул. Но я бы не стал рассказывать как именно надо это делать — ну потому что кто-то прочитает, скажет «ах, guru know...» и сделает именно это.
Ладно, тут похоже философский вопрос из серии — если ЯП позволяет простреливать себе коленки — надо ли всем программистам этим заниматься.
В общем, извините за занудство, вам наверное виднее, что надо писать. Только зачем тогда спрашиваете -«Не уж-то так плохо написал?»
Ладно, тут похоже философский вопрос из серии — если ЯП позволяет простреливать себе коленки — надо ли всем программистам этим заниматься.
В общем, извините за занудство, вам наверное виднее, что надо писать. Только зачем тогда спрашиваете -«Не уж-то так плохо написал?»
-3
Тогда посоветуйте, про что же такое Великое можно написать?
0
Да вроде как предлагал уже, но вы Реймонда Чена можете рассказывать и без всякой статьи. Но что-то я сильно сомневаюсь что вы этот вопрос задавали с намерением слушать ответы на него.
+1
Про C#?
Сделайте обзор коллекций в стандартной библиотеке .NET 4.0, к примеру. Я не один и не два раза сталкивался с тем, что люди реализовывали (причем довольно криво) то, что можно было просто взять и использовать.
Сделайте обзор коллекций в стандартной библиотеке .NET 4.0, к примеру. Я не один и не два раза сталкивался с тем, что люди реализовывали (причем довольно криво) то, что можно было просто взять и использовать.
+2
Так же можете написать про неуправляемые ресурсы, там хватает заморочек.
0
Сумбурно как-то. Об вот такие вещи "Не смотря на её название, это вовсе не означает, что вся сборка мусора теперь происходит в дополнительных фоновых потоках выполнения. На самом деле в случае фоновой сборки мусора для объектов, не относящихся к эфемерному поколению, исполняющая среда .NET теперь может проводить сборку мусора объектов эфемерного поколения в отдельном фоновом потоке." можно мозг сломать. Вроде бы и понятно, а над каждым вторым предложением приходится медитировать, вчитываясь в предыдущие и выстраивая логическую цепочку из высказываний. В данном конкретном примере во втором предложении явно не хватает слова «только» и лишнее слово «теперь» — спотыкаешься и начинаешь думать «по сравнению с чем теперь?» и «а что же с остальными поколениями?». И таким моментов много.
А в целом интересно даже на теме, про которую тут уже много раз писали.
А в целом интересно даже на теме, про которую тут уже много раз писали.
0
Спасибо, интересно было почитать. Самому не так давно приходилось с этим заморачиваться, но только, чтобы работать с оборудованием через неуправляемую библиотеку. А вообще, автоматическое управление памятью — это такой кайф. ^_^
0
Позвольте с вами не согласиться. С одной стороны явный плюс с точки зрения performance и «легкого» исключения человеческого фактора. С другой стороны, лично я, не могу чувствовать себя комфортно не используя в ряде случаев ручного управления.
0
Исправьте меня, если не прав, но даже в случае «перехода» на полностью ручное высвобождение памяти никаких проблем не возникает (за исключением небольшой деградации performance по сравнению с автоматическим режимом и, как уже было выше сказано, возможных «ошибок», приводящих к утечкам памяти).
0
В данном случает я могу сказать только одно: «Все мы люди». Совершенных программ не бывает. Лично я не вижу смысла переходить на ручное управление там, где это просто не надо.
0
Человеческий фактор понятен, тут нет вопросов. По остальным моментам тоже согласен. Я всю эту демагогию развел только по той причине, что .Net для меня немного в новинку в плане сборки мусора после Delphi/C++ и в силу привычки к методике написания кода, когда любое порождение сразу же обрамляется высвобождением, мне иногда тяжело перестроиться.
0
Хорошая обзорная статья, но не более.
Несколько замечаний:
1. > Идентифицирует объект, который уже «пережил» один процесс сборки мусора (был помечен, как надлежащий удалению, но не был удалён из-за достаточного свободного места в куче).
Мне кажется, в скобках не хватает слов «в том числе» — так как объект может пережить сборку мусора, и не будучи помеченным как мусор.
2. Вы красиво рассказали про основы и поколения, но совершенно не раскрыли тему списка финализации — как же так, зачем тогда его упоминать? А воскрешение объектов (на которые снова есть указатель в корневом элементе, и которые подлежат финализации, но не считаются в этот момент мусором? А возможность пересоздать объект во время этой самой финализации?
3. Вы не сказали, что будет, если даже после очистки 2го поколения памяти не хватит.
Несколько замечаний:
1. > Идентифицирует объект, который уже «пережил» один процесс сборки мусора (был помечен, как надлежащий удалению, но не был удалён из-за достаточного свободного места в куче).
Мне кажется, в скобках не хватает слов «в том числе» — так как объект может пережить сборку мусора, и не будучи помеченным как мусор.
2. Вы красиво рассказали про основы и поколения, но совершенно не раскрыли тему списка финализации — как же так, зачем тогда его упоминать? А воскрешение объектов (на которые снова есть указатель в корневом элементе, и которые подлежат финализации, но не считаются в этот момент мусором? А возможность пересоздать объект во время этой самой финализации?
3. Вы не сказали, что будет, если даже после очистки 2го поколения памяти не хватит.
+2
Про финализацию я собирался написать в продолжении этой статьи. Но судя по всему, она никому не понадобится, так что я не вижу смысла для себя заморачиваться.
Спасибо Вам за поправки, потому что это моя первая статья и она по определению не могла быть идеальной)
Спасибо Вам за поправки, потому что это моя первая статья и она по определению не могла быть идеальной)
+1
Я просто к тому, что если что-то упоминается в статье — лучше это хоть как-то объяснить. Для более цельной картины.
0
Внеси, пожалуйста, в статью вышеуказанные поправки, особенно из пункта 1, а то у тебя получается что мусор может дойти аж до второго поколения.
А вообще в джаве интереснее читать статьи про сборку мусора, перлы вроде «Большинство объектов умирают молодыми в раю» доставляют. И названия поколений более понятные:
0 — Young, Eden: молодое поколение, Рай
1 — Survivor: оставшиеся в живых
2 — Old, Tenured: старые, штатные объекты
А вообще в джаве интереснее читать статьи про сборку мусора, перлы вроде «Большинство объектов умирают молодыми в раю» доставляют. И названия поколений более понятные:
0 — Young, Eden: молодое поколение, Рай
1 — Survivor: оставшиеся в живых
2 — Old, Tenured: старые, штатные объекты
+1
>>Вы не сказали, что будет, если даже после очистки 2го поколения памяти не хватит.
Вылетит OutOfMemoryException или InsufficientMemoryException
Вылетит OutOfMemoryException или InsufficientMemoryException
0
Примеров хотелось бы побольше. А то получился совсем уж откровенный пересказ Троелсена.
0
Я просто слабо представляю, какие примеры можно здесь привести здесь.
+1
А вы прочитайте (или перечитайте) главу у Рихтера — там как раз в связке с финализатором и слабыми ссылками предлагается реализация кэширования.
+1
Ощущение что статья чисто для галочки на itbonus или чем-то подобном. Куча воды, практически 0 полензной информации и куча нюансов упущена. Не рассказанно про вторую кучу, совершенно не упомянуто ни одих грабель, которые приводят к утечкам памяти в .net. Если все-таки «золотое правило» в кавычках именно потому что оно наоборот — вредное — то нигде в статье этого не говорится, если же действительно полагается, что все объекты, ссылки на которые вы больше никак не можете получить — удалятся — то это непонимание принципов. В .net утечки памяти могут возникнуть (bingo!) даже если все объекты действительно уже финализированы и удалены.
Далее — когда говорят «стал оптимальным» все же подразумевается, что лучше некуда, а тут лучше есть куда, еще очень и очень много куда развиватсья есть.
Честно — даже на обзорную статью не тянет, уж слишком много концептуальных кусков опущенно, описанно по верхам и всего пара аспектов.
Ну и в конце концов, когда вы пишете «new smth()» — это совсем не значит что объект попадет вообще хоть в какую-то кучу.
Далее — когда говорят «стал оптимальным» все же подразумевается, что лучше некуда, а тут лучше есть куда, еще очень и очень много куда развиватсья есть.
Честно — даже на обзорную статью не тянет, уж слишком много концептуальных кусков опущенно, описанно по верхам и всего пара аспектов.
Ну и в конце концов, когда вы пишете «new smth()» — это совсем не значит что объект попадет вообще хоть в какую-то кучу.
+8
>>Использование ключевого слова new приводит к добавление объекта класса в так называемую управляемую кучу, а назад возвращается ссылка на объект.
У value-типов такого не происходит.
Если уж совсем залезть в дебри, то инструкция newobj кладет новый объект (вне зависимости от типа) в стек. Уже после объект берется из стека и т.д.
У value-типов такого не происходит.
Если уж совсем залезть в дебри, то инструкция newobj кладет новый объект (вне зависимости от типа) в стек. Уже после объект берется из стека и т.д.
0
UFO just landed and posted this here
Ухты, интересно, я только начал писать на шарпе, и столкнулся с непонятными для меня, назовем их «багами», связанными со сборщиком мусора, а вот оказывается как оно бывает. Спасибо за информацию (и о новой редакции книги тоже).
0
Вы уверенны что это именно те «баги»? Просто именно аспекты сборки мусора (если все остальное сделанно правильно) приводят только к утечкам памяти, а их «багами» обычно не называют.
0
Я поэтому и взял в кавычки, не совсем конечно уверен что, как и где (я в процессе понимания), но одно знаю точно — объект зачищали без моего указания и ведома. И я не понимал почему я вижу исключение которого быть не должно.
0
Проще выложите код, если там никакой сверх-магии нет — напишу причину бага.
0
Не знаю уместно ли тут обсуждать конкретный код, но в общем суть в чем — нужно хранить глобальный массив форм, что бы из любого места всем они были доступны. Для этого я использовал Dictionary<string, MyForm>, ну и почему-то при добавлении очередной формы в массив она просто уничтожалась и при попытке её показать возникало ObjectDisposedException.
0
Разве такое возможно вообще? C# запрещает хранить глобальные объекты
0
ObjectDisposed — это не «уничтожалась», это значит что кто-то вызвал у формы метод Dispose (что к GC не имеет отношения). С формой такое может происходить если вы вызываете у объекта формы Close(), а потом пытаетесь показать его.
0
Ну или если форма любым образом получает сообщение о закрытии, напр. WmClose. Или если система вызывает у нее Dispose.
0
Ага, интересненько, правда Close вроде бы никто не вызывает, а пока сделал проверку isDisposed, но вообще надо будет подумать где я накосячил…
0
Сделайте в своем классе override Dispose(bool) (он выше по иерархии объявлен как виртуальный и вызывается из обычного Dispose() класса Component()) и поставьте там точку останова, потом пошаговой отладкой поймаете, кто вызывает.
0
Раз уж обсуждем конкретный код — то лучше использовать стандартный статический System.Windows.Forms.Application.OpenForms, с поиском по имени.
+1
Sign up to leave a comment.
Сборщик мусора в среде .NET