Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>>Ну и потом, это не только из unmanaged, такой же подход используется в Java. Собственно, пулы хорошо решают задачу снижения издержек конструирования объектов, распределение памяти — только часть этой задачи.
G>Если объекты "тяжелые", то такой подход оправдан. Но сама операция выделения памяти в managed очень быстрая (по сути interlocked increment), затраты вносит сборка мусора которая зависит от количества живых объектов. Это значит что чем меньше остается живых перед сборкой мусора — тем лучше.
Поправка: по сути операция выделения памяти в дотнете еще быстрее, чем interlocked increment. Вот, вытряхнул таки пыль из Рихтера о дотнете 2.0:
Выделение памяти без синхронизации
В многопроцессорной системе поколение 0 управляемой кучи разделено на несколько арен памяти — по одной на каждый поток. Это позволяет нескольким потокам выделять память одновременно, не требуя монопольного доступа к куче.
Здравствуйте, gandjustas, Вы писали:
G>для начала long в C++ и long в C# — не одно и то же.
Я это знаю, поэтому в C++-варианте используется long long. Выбрано ради 8-байтовой длины, чтобы на x64 поменьше неожиданностей было.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Sinclair, Вы писали:
ГВ>>Хорошо, пусть это будет "анализ состояния памяти". Хотя большой разницы нет: проанализировать и принять решение на основании анализа, считай, то же самое, что и: "проверить и принять решение на основании результата проверки". Разница в оттенках. S>Нет никакого "решения", нет никакого "анализа". S>Есть процедура "спасение живых объектов". Нет процедуры "удаление мёртвых объектов". S>В классическом менеджере памяти нет процедуры "спасение живых объектов", зато есть процедура "удаление мёртвых объектов". S>Этих несложных соображений пытливому уму должно быть достаточно для того, чтобы прикинуть, где должна пролегать граница между "GC эффективнее" и "классика эффективнее".
Пытливый ум при этом задаст ещё один вопрос: а что делать потом с фрагментированной свободной памятью? При этом граница эффективности как-то размывается...
S>И уж тем более достаточно для того, чтобы навсегда отказаться от заблуждений вроде "классика всегда эффективнее".
Хр-р-р пс-пс-пс... Хр-р-р пс-пс-пс...
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Пытливый ум при этом задаст ещё один вопрос: а что делать потом с фрагментированной свободной памятью? При этом граница эффективности как-то размывается...
Совершенно верно. Фрагментация свободной памяти, которой подвержены классические менеджеры памяти — это ещё один аргумент в пользу GC.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
ГВ>>Пытливый ум при этом задаст ещё один вопрос: а что делать потом с фрагментированной свободной памятью? При этом граница эффективности как-то размывается... S>Совершенно верно. Фрагментация свободной памяти, которой подвержены классические менеджеры памяти — это ещё один аргумент в пользу GC.
Неправильно. Это аргумент в пользу отказа от классических менеджеров памяти. Ещё варианты есть?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, vdimas, Вы писали:
V>Отличие лишь в том, что стек трейс виден детальный, т.е. быстрее можно найти ошибку (если она не та самая наведенная )
Это точно, еще как быстрее.
И ты за всем пустословием упустил самое главное. В управляемом коде надо еще постараться, чтобы получить наведенную ошибку. А в С++ надо очень постараться, чтобы их не получить.
Здравствуйте, Геннадий Васильев, Вы писали: ГВ>Неправильно. Это аргумент в пользу отказа от классических менеджеров памяти. Ещё варианты есть?
Хорошо, сформулируем по-другому: фрагментация свободной памяти возникает в ручном подходе к выделению памяти. И является, таким образом, аргументом для отказа от ручного распределения в пользу автоматического выделения памяти, т.е. GC.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Klatu, Вы писали:
V>>Отличие лишь в том, что стек трейс виден детальный, т.е. быстрее можно найти ошибку (если она не та самая наведенная ) K>Это точно, еще как быстрее. K>И ты за всем пустословием упустил самое главное. В управляемом коде надо еще постараться, чтобы получить наведенную ошибку. А в С++ надо очень постараться, чтобы их не получить.
Ты снова говоришь только об ошибках, наведённых неправильной работой с памятью, или на этот раз имеешь в виду все наведённые ошибки?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Геннадий Васильев, Вы писали: ГВ>>Неправильно. Это аргумент в пользу отказа от классических менеджеров памяти. Ещё варианты есть? S>Хорошо, сформулируем по-другому: фрагментация свободной памяти возникает в ручном подходе к выделению памяти. И является, таким образом, аргументом для отказа от ручного распределения в пользу автоматического выделения памяти, т.е. GC.
Снова неправильно. Фрагментация возникает тогда, когда реализованная в программе политика управления жизненным циклом объектов подразумевает такую фрагментацию. Ещё варианты?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, samius, Вы писали:
S>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>>>Ну и потом, это не только из unmanaged, такой же подход используется в Java. Собственно, пулы хорошо решают задачу снижения издержек конструирования объектов, распределение памяти — только часть этой задачи.
G>>Если объекты "тяжелые", то такой подход оправдан. Но сама операция выделения памяти в managed очень быстрая (по сути interlocked increment), затраты вносит сборка мусора которая зависит от количества живых объектов. Это значит что чем меньше остается живых перед сборкой мусора — тем лучше. S>Поправка: по сути операция выделения памяти в дотнете еще быстрее, чем interlocked increment. Вот, вытряхнул таки пыль из Рихтера о дотнете 2.0: S>
S>Выделение памяти без синхронизации
S>В многопроцессорной системе поколение 0 управляемой кучи разделено на несколько арен памяти — по одной на каждый поток. Это позволяет нескольким потокам выделять память одновременно, не требуя монопольного доступа к куче.
Насколько я сылшал серверный GC позволяет параллелить в первую очередь сборку мусора, а не выделение памяти. interlocked increment и так довольно быстр чтобы еще и его пытаться оптимизировать.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, samius, Вы писали:
G>>>Если объекты "тяжелые", то такой подход оправдан. Но сама операция выделения памяти в managed очень быстрая (по сути interlocked increment), затраты вносит сборка мусора которая зависит от количества живых объектов. Это значит что чем меньше остается живых перед сборкой мусора — тем лучше. S>>Поправка: по сути операция выделения памяти в дотнете еще быстрее, чем interlocked increment. Вот, вытряхнул таки пыль из Рихтера о дотнете 2.0: S>>
S>>Выделение памяти без синхронизации
S>>В многопроцессорной системе поколение 0 управляемой кучи разделено на несколько арен памяти — по одной на каждый поток. Это позволяет нескольким потокам выделять память одновременно, не требуя монопольного доступа к куче.
G>Насколько я сылшал серверный GC позволяет параллелить в первую очередь сборку мусора, а не выделение памяти. interlocked increment и так довольно быстр чтобы еще и его пытаться оптимизировать.
Речь шла о выделении памяти. То что в многопроцессорном GC используется несколько арен поколения 0 — не я придумал. А раз используется несколько арен, то interlocked там и не нужен. Т.к. насколько бы он не был быстр, он значительно медленне простого инкремента.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Klatu, Вы писали:
K>>А про плавающие и косвенные ошибки ты решил скромно умолчать, или просто не в курсе что это такое?
V>Это от технологии не зависит.
Вот тут не уверен. Когда разрабатываешь один продукт, состоящий из разных компонент и когда разные компоненты делают разные отделы, и при этом один компонент портит память другому, то непонятно даже на какой компонент баг вешать. Вот и приходится мне, как продуктовому разработчику, сидеть в windbg и ковыряться в компонентах, к которым я вообще отношения не имею, кто кому портит память, просто чтобы понять, кому вешать баг. Мне что, больше заняться нечем? Вот и думаешь в такие моменты: писали бы все на .NET'e или яве, как бы проще жить было!
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ> Первый раз я это услышал от спеца, принёсшего весть не то с конференции MS, не то с какой-то UG в 1997-м: что, мол, "сейчас главное — разрабатывать программы быстро, а то, что форма рисуется не за 200 микросекунд, а за 200 миллисекунд — так кому какая разница!" и тут же: "MS считает, что сейчас цикл разработки программы — 2 месяца" (последняя цифра мне особенно в память врезалась).
Вот уж не знаю, везде ли так, как у меня, или не везде. Но и скорость работы спеца нафиг никому не упёрлась. Я тут со своей эффективностью сижу и жду, когда же бизнес решит, чего он хочет. От нечего делать попиваю чаёк и читаю RSDN. Так что мем зародился именно из-за безалаберности. При желании можно и эффективный код писать быстро. Я понимаю, были бы какие-то сложные алгоритмы, где надо полгода думать, как от вместо O(n*log(n)) перейти к полиномиальной сложности. А тут же формочки с БД! Написание эффективного кода в таких условиях превращается из сложной задачи в банальный навык, зашитый в спинном мозге.
K>И ты за всем пустословием упустил самое главное. В управляемом коде надо еще постараться, чтобы получить наведенную ошибку.
Легко! Наведенная ошибка — это практически любая неправильно обработанная ошибка или пропущенная где-то ранее ошибка. Самый очевидный пример — когда-то ранее null сохранили без проверки, а в момент использования получи ошибку. Вот тебе классическая наведенная ошибка, найти которую не поможет никакой стек-трейс, т.к. в момент возникновения ошибки ее предыстория неизвестна. Она встречается на несколько порядков чаще в дотнете, да и в нейтиве тоже, чем проходы по памяти. По-сути ты называешь главной причиной наведенных ошибок ту, которая составляет доли одного процента от всех причин для наведенных ошибок. Сие нелепо.
K>А в С++ надо очень постараться, чтобы их не получить.
Разве?
И ты за всем пустословием упустил самое главное.
Ну так напомню, что ты и тебе подобные постоянно игнорируют тот факт, что всякие переполнения буфера происходят в основном в legacy-коде, который был писан черти когда на голом С или на самых первых версиях C++, на котором все-равно писали как на С. Уже более 10-15 лет никто не создает в С++ массивы памяти вручную. Стал бы ты, даже имея такую возможность в дотнете (а она есть, через класс Marshal) выделять и вручную следить за блоками памяти? Это же жутко неудобно! Аналогично и в С++ — использование безопасных библиотек удобнее гораздо, банально меньше кода, и голова не болит следить за байтами.
Откуда же такое внимание к ошибкам именно в нейтиве? Наверно от того, что из нейтива можно сделать гораздо больше, чем из дотнета, в плане злонамеренно навредить, т.к. все АПИ ОС всё еще нейтивные. А ты тут на весь интернет путаешь частоту проявления ошибки с ее важностью. К тому же, сам факт спора о технологии, которой недостаточно владеешь, профанирует весь спор. Я постоянно последние почти лет 10 (еще с первых бет) использую как С#, так и C++. И какой аспект не возьми, но организовать на С++ статическую проверку всегда проще, чем на C#, на котором каждую мелочь, отсутствующую в стандартных либах, надо писать вручную. Дотнет хорош своей огромной функциональностью, данной на халяву, а так же визуальными редакторами GUI. Но в плане кол-ва словленных ошибок... если не касается использование имеющихся библиотек, а нужно некую функциональность делать практически с 0-ля, то программисты C# допускают намного больше ошибок, чем программисты на C++. Как раз из-за более бедных языковых ср-в. Причем, это медицинский факт, который я подметил еще в первые 3-4 года дотнета. Хотя, всякие FxCorp и Resharper помогают (частично), но тогда этих инструментов не было, и прелести технологии были видны во всей красе. Из-за этого что-то делать с 0-ля на дотнете в те времена можно было только в явовском стилее TDD, ввиду невозможности обложить код достаточными статическими проверками, нивелирующими надобность в ~90% этих тестов. А если брать ситуацию на сейчас, то под С++ уже полно ср-в как статического анализа кода, так и динамического. Серьезных, прямо скажем ср-в, аналогов которых под дотнет еще ждать и ждать.
В общем, повторю, возможность писать безопасно на С++ есть, и эта возможность на этапе компиляции всяко пошире, чем на C#. Возможность писать небезопасно тоже есть, но это считается хакерством, как беспричинный unsafe в дотнете, полностью аналогично. Ну и тыкать плюсовиков ошибками в старом С-коде — это надо совсем не разбираться в технологиях.
Здравствуйте, samius, Вы писали:
ГВ>>Так именно такой сценарий и следует из слов gandjustas. И в принципе, он имеет право на существование. S>Право имеет, но вряд ли такой сценарий в большей мере относится именно к программистам C++.
ХЗ... В С++ короткоживующие объекты, являющиеся полями других объектов, обычно хранятся как value-type (т.е. имеют семантику значений). Перетягивая эту привычку на дотнет я зачастую делаю так же, а не то, что изобретает себе gandjustas.
Здравствуйте, gandjustas, Вы писали:
G>Например в создании долгоживущих объектов без необходимости. Вроде создания пула объектов для уменьшения количества выделений памяти (довольно частая оптимизация в unmanaged) в managed может приводить к отрицательным результатам.
Может, не может... что за гадания на кофейной гуще?
Когда вводят пул объектов, то делают это под постоянным присмотром через результаты тестирования производительности. Я даже боюсь себе представить твою ситуацию "умозрительного" применения пула объекта, т.е. вне процедур по увеличению эффективности кода, со всем тем, что эти процедуры сопровождает.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>>А в чём? Интересно было бы узнать твоё мнение.
AVK>Как обычно — кривые алгоритмы, кривой дизайн, плохое сопряжение независимых кусков кода и косяки в стандартных библиотеках.
А почему тогда приложения на плюсах работают быстрее? Там алгоритмы лучше или с дизайном дела как-то иначе обстоят?
Здравствуйте, samius, Вы писали:
S>Поправка: по сути операция выделения памяти в дотнете еще быстрее, чем interlocked increment. Вот, вытряхнул таки пыль из Рихтера о дотнете 2.0: S>
S>Выделение памяти без синхронизации
S>В многопроцессорной системе поколение 0 управляемой кучи разделено на несколько арен памяти — по одной на каждый поток. Это позволяет нескольким потокам выделять память одновременно, не требуя монопольного доступа к куче.
Это касается только маленьких объектов. Для больших, по-прежнему пулы показывают оч. высокую эффективность, в сравнении с GC. Например пуллы массивов байт/символов.
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Хорошо, пусть тогда это будет апериодический процесс, который вызывается по заполнении очередного сегмента (area). Скажи пожалуйста, как понимать выражение: "строится граф живых объектов"? AFAIK, чтобы построить такой граф, нужно пройти по ссылкам и как минимум, убедиться, что проверенные ссылки не нулевые. Или нет?
Угу, и когда объектов много и у этих объектов очень ветвистые графы в памяти, то сборка GC может занимать заметные доли секунд и даже несколько секунд. Сочетание параллельного GC и фонового немного смягчает этот эфект, растягивая сборку поэтапно по времени.