Комментарии 230
эм, на биржевых серверах время отклика измеряется единицами и долями микросекунд, какие, к чёртовой бабушке, там 50 мс на сборщики мусора?
Например, если у нас поступает 10К запросов с секунду, то за 200мс задержки размер очереди запросов (внезапно) увеличивается на 2К штук. Эти 2К запросов будут обработаны тоже с задержкой (независимой от GC), просто потому что ресурсов будет недостаточно, чтобы их все обрабатывать параллельно (условно, 1980 запросов будут ждать пока отработают 20, потом 1960 будут ждать завершения обработки следующих 20 шт и т.д.). При неблагоприятных условиях размер очереди будет дальше увеличиваться лавинообразно (говорю не понаслышке, встречал такие ситуации неоднократно — и из-за пауз GC, и из-за пауз при доступе к memcached и redis..)
Так что для серверного применения уменьшение длительности задержки в разы ценой 10-20% дополнительной нагрузки на CPU более чем оправдано.
Насколько я помню, применяется метод нескольких пулов страниц по размеру. Допустим, менеджер памяти откусывает страницы по 4 килобайта. Мы создаём несколько пулов объектов — 32, 64, 128, 256, 512, 1024, 2048 байт. Всё что больше — выделяется непрерывными кусками без особых заморочек. Как результат такой "сегрегации" — проще найти дырку под новый объект на месте удалённого.
Хранение списка свободных страниц и его поддержание требует ресурсов.
Последовательное выделение в таком пуле приводит к не последовательному выделению памяти (теряется colocation), что ухудшает попадание данных в кэш — всегда ли этим можно пренебречь?
Выделение на объект больше памяти, чем необходимо, из-за пулинга тоже отрицательно влияет на попадание в кэш.
Я не готов утверждать, что все это в каких-то случаях приведет к выигрышу GC, но может когда-то соберусь написать бенчмарки.
Мне кажется, вы сравниваете с конкретно Generational GC — у которого тоже есть свои проблемы. Но не будем, тут действительно нужно писать бенчмарки — и притом не тривиальную сумму миллиона чисел в массиве.
Лично для меня преимущество у не-GC языков в большей управляемости и, что важнее, едином в меру удобном механизме работы с любыми ресурсами — не только памятью. В управляемой среде нетривиальный сценарий работы с тем же файлом, критической секцией, COM-объектом или кустом реестра превращается в мороку. В С++ и Расте компилятор хоть деструкторы сгенерит.
В том же C# есть
using(var resource = new MyUnmanagedResource) {
# do something with resource
} # auto dispose resource
Я в курсе. Как по мне, это костыль.
Два недостатка:
- Менеджмент ручками. Ответственность за удаление перекладывается с автора кода ресурса на пользователя. Забыли юзинг — ресурс освободится неизвестно когда, если вообще освободится.
- Как только ресурс живёт дольше области видимости одной функции — using блок становится бесполезен
- Вы ещё скажите что в С++ на пользователе ресурса нет никакой ответственности и он не может забыть использовать смарт-поинтер и забыть написать delete. Плюс адекватные IDE вам частенько подсветят, если вы чего забыли.
- При правильном дизайне это решается тривиально. Если ресурс надо закрывать при окончании использования владельца (условно при его деструкции), то владелец объявляется новым ресурсом (в джава интерфейс
AutoCloseable
) и уже его пользователи используют using/twr. Если жизненный цикл более мутный, на помощь придут пулы ресурсов. Собственно у меня начиная с седьмой джавы не было никаких проблем с ресурсами в новом коде. До этого действительно бойлерплейта было много и можно было неаккуратно закрыть всё в исключительных ситуациях, что могло приводить к утечкам. Сейчас об этом особо думать не надо.
2. При совместном использовании ресурса из нескольких потоков AutoCloseable не поможет.
Этот подход работает почти всегда, но не всегда. Например если между "передачей" или созданием ресурса и завершением конструктора "приемщика" происходит исключение, например какой-нибудь NPE или ISE, ресурс утечет, если не добавить try-catch Throwable. Вроде бы NPE/ISE быть "не должно", но если не добавить этот боилерплейт, сервер может быть дестабилизирован: вместо "иногда на определенных запросах валится с исключением" получаем то же самое + "постепенно течет и со временем валится полностью", по исчерпанию direct memory или какого-нибудь пула коннектов, например.
В Java 7 появилось
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
полный аналог C# using.
Это скорее результат старого проверенного подхода "всё есть ресурс в т.ч. память". Кстати, это одна из проблем языков со сборкой мусора — работа с временем жизни неуправляемых ресурсов превращается в редкий геморрой вне самых простых сценариев.
Не вижу, чтобы в джаве с этим было больше геморроя, чем в С++. Вы много управляли ресурсами в языках со сборкой мусора? Приведите пример, когда в джаве/шарпе с ресурсом геморрой, а в плюсах аналогичная проблема решается легко и просто.
В Java гораздо сложнее управлять связками управляемой и неуправляемой памяти, в C++ это одно и то же
У раст-подхода есть свои недостатки и достоинства. Например, большое кол-во маложивущих объектов в куче вызовет, скорей всего, приличные расходы на аллокацию и gc. А если это делается в несколько потоков, то можно нарваться на false sharing (это предположение), что просадит производительность раз 100..1000. В java первоначальная аллокация происходит в своей для каждого потока области, И возможно даже, что адреса областей выбраны так, чтобы физическая память мапилась в логическую не образовывая списки, и плюс всякие другие фишки.
А еще в раст не очень понятно, как работать с циклическими ссылками.
Раст хорош по-своему, но не идеален. Надо это понимать.
Например, большое кол-во маложивущих объектов в куче вызовет, скорей всего, приличные расходы на аллокацию и gc.
Такие объекты лучше будет прямо на стеке и создать, если есть возможность.
А еще в раст не очень понятно, как работать с циклическими ссылками.
Понятно, но не особо удобно. (:
Так это достоинство, а не недостаток! Типичная файловая система в принципен с циклическими ссылками работать не может — и ничего, это не мешает в ней хранить всё, что придумало человечество, почему-то.А еще в раст не очень понятно, как работать с циклическими ссылками.
Понятно, но не особо удобно. (:
Циклические символические ссылки никуда не делись. Полагаю, это должно быть что‐то вроде аналога слабых ссылок? В любом случае, циклические ссылки есть, с ними «работают», но отваливаются они по количеству переходов, а не потому, что кто‐то нашёл цикл.
P.S. Но мы то знаем кто из них на самом деле жрет больше памяти :)
Грубо говоря, если увеличение памяти сокращает продолжительность паузы, то значит, размер памяти не соответствовал масштабу задачи. А если не сокращает, а просто делает их реже — значит либо плохо написана программа, либо плохой gc. Конечно, это грубо.
Вообще, full gc это такой костыль, который призван кое-как компенсировать негативный эффект от повышенного пожирания памяти. В с++ нет никакого full gc, Если памяти для плюсовой проги не хватит — то прога скорей всего просто упадет и никому в голову не приходит «оптимизировать дырки в хипе», просто говорят, мол, это большая задача — и добавляют памяти. Но для java такой подход почему-то неприемлят — и начинают ругать gc.
А в С++ есть сборка мусора?
Вы к пустяку придрались, к словам. Речь была о том, что есть плюсовой подход: не латаем дырки в куче, а говорим сразу — не шмогла, дай памяти. И есть java подход: латаем дырки и жалуемся, что тормоза.
p.s. вообще есть boehm gc напрмиер. Но к делу это не относится.
Не отвечайте. Вопрос не корректный. Т.к. всё зависит не только от GC, но еще и от задачи.
На разных задачах разные GC будут показывать разные результаты. Об этом и статья.
Если так то разумный выбор т к го генерирует меньше мусора в памяти и использует довольно компактные типы данных
Казалось бы, сборка мусора должна решить эту проблему. Но идут годы, а мы читаем одни и те же статьи, про то, как разработчики языков улучшают сборщики мусора и вот-вот сделают всем хорошо (хотя их работа — мега сложная). А команды разработчиков пишут уже о двух проблемах. О том, как они решают проблемы с несвоевременным освобождением внешних ресурсов (финализаторы порой вызываются когда им вздумается) и про то, как они героически тюнили сборщик мусора под их высоконагруженный проект. (И, конечно, в конце-концов победили. По крайней мере, пока.)
Вам не кажется, что для сложных проектов сборка мусора создаёт большем проблем, чем решает?
Про уровень hello, world речь не идёт. Там и редкие секундные паузы проблем не вызовут. А скорее всего и их не будет из-за малого количества потребляемой памяти и создаваемых объектов.
И с каждым улучшением GC Java (вплоть до специально для Cassandra написанного) все пользователи
будут получать улучшение производительности или репортить баг и получать улучшение производительности.
И есть scylladb (не умаляю труда разработчиков), которая год назад только и умела, что сыпать краш дампы.
Для меня лично плюс GC в том, что я уже получаю тысячи часов работы умных людей и могу решать задачу.
А если мне понадобится оптимизировать какое-то место, то есть умные коллеги, которые сделают выбор
free vs delete или, что скорее, скажут заменить O(n^3) на O(n)
Но если б не было сборки мусора, статьи бы не было. Не потому, что проблемы бы не было, а потому что продакшна бы не было. Проект бы просто не вышел на рынок и загнулся из-за нехватки финансирования.
Вам не кажется, что для сложных проектов сборка мусора создаёт большем проблем, чем решает?
Она создает проблемы несравнимо более простые, чем над огромным проектом пыхтеть и трястить за каждый delete, а потом хрен знает сколько отлавливать одни из самых распространенных багов, которые очень сложно найти — работы с памятью. И эти проблемы будут жить с проектом всю его жизнь. Сборщик если и начнет мешать, то скорее всего его придется раз-два настроить, и он будет дальше работать и облегчать работу. Это существенно проще, как по мне, чем ловить утечки и повреждения кучи.
Хотя, компилятор тоже идеализировать не стоит. На текущий момент хорошего, универсального решения нет.
Речь же о том, почему используется GC, а не смарты? GC заявляется панацеей от необходимости контролировать время жизни объектов. При этом несет много проблем с собой. Смарты тоже убирают проблему контроля времени жизни. При этом дают минимальные накладные расходы и не требуют выполнения в фоне дополнительных плохо контролируемых процессов.
2. GC — это не только, собственно, контроль за временем жизни. Это ещё и компилятор, который знает, что работает с GC, и старается под этот GC оптимизировать. И это удобнее. Потому что при переписывании кода не нужно заботится о том, что вот здесь мы теперь должны weak_ptr менять на shared, а вот тут shared можем поменять на unique, и наступит счастье. А где-то мы забыли поменять, и счастье не наступило, но мы об этом даже не узнаем, пока production не отвалится. Когда за анализ указателей отвечает компилятор — работать проще.
3. Вообще, по опыту, в реальности, почти всегда приходится писать нечто похожее на GC в каждом чуть более сложном, чем hello world, проекте. У алгоритмов, которые работают со сложными структурами данных, просто карма такая.
4. Ну, и как бы, я не утверждаю, что GC панацея. Серьёзных проблем много и с GC, и без GC. В конце концов, вон ребят из Mozilla так достали умные указатели, что они аж новый язык решили изобрести. Идеального решения на сегодняшний день нет. Но если оно вообще возможно, то всё же, на пути усовершенствования сборщиков мусора и, скорее всего, языков программирования.
Речь же о том, почему используется GC, а не смарты? GC заявляется панацеей от необходимости контролировать время жизни объектов. При этом несет много проблем с собой. Смарты тоже убирают проблему контроля времени жизни. При этом дают минимальные накладные расходы и не требуют выполнения в фоне дополнительных плохо контролируемых процессов.
Например, потому, что GC всё-таки даёт ощутимо меньшие накладные расходы, чем смартпоинтеры, в том числе по памяти (GC не требуют тащить дополнительные 32 бита на объект для счётчика). Особенно в многопоточном коде. А ещё у смартпоинтеров проблема с циклическими ссылками. А ещё GC уплотняют кучу, этим улучшая локальность доступа к памяти (знаю, современные алгоритмы malloc умеют частично решать проблему фрагментации памяти, но ключевое слово — частично).
В итоге, счётчик ссылок лучше подходит только в достаточно узкой нише, там где очень важно детерминированное время задержки, это всякая кровавая эмбедщина или кровавый хайлоад с каком-нибудь высокочастотном трейдинге. Для остальных задач, коих тьма, GC подходит лучше. Кстати, существуют специализированные GC, которые ценой определённых накладных расходов умеют сильно снижать время задержки. Гуглить например metronome GC.
Например, потому, что GC всё-таки даёт ощутимо меньшие накладные расходы, чем смартпоинтеры, в том числе по памятиЭто с какого перепугу? Какие-такие накладные расходы при использовании какогого-нибудь unique_ptr?
А ещё у смартпоинтеров проблема с циклическими ссылками.Госсподя. Далась вам эта проблема. Что, с GC у вас ресурсы утегать не будут? Будут, ещё как будут, если вы запутаетесь в том кто и когда ими владеет. Иначе бы подобные ужасы были бы не нужны. А если вы знаете кто, когда и почему владеет ресурсом, то уж как-нибудь с циклическими ссылками разберётесь, чесслово.
А ещё GC уплотняют кучу, этим улучшая локальность доступа к памяти (знаю, современные алгоритмы malloc умеют частично решать проблему фрагментации памяти, но ключевое слово — частично).Какое, блин, достижение. А в цифрах — не, не покажите? Что именно вам это даёт? И как часто? С точки зрения конечного пользователя, пожалуйста.
В итоге, счётчик ссылок лучше подходит только в достаточно узкой нише, там где очень важно детерминированное время задержки, это всякая кровавая эмбедщина или кровавый хайлоад с каком-нибудь высокочастотном трейдинге.Всё как раз наборот. Иначе вот этого бы не было. Поверьте — у Apple есть много недостатков, но умения создать красивые, приятные в работе, программы — у них не отнять. И вот для них — GC противопоказан.
Это с какого перепугу? Какие-такие накладные расходы при использовании какогого-нибудь unique_ptr?
Ну всё-таки давайте будем честны, всю программу на одних только unique_ptr не напишешь. Плюс возникают накладные расходы на создание программы (думать, кто каким объектом владеет). А так, для общего случая нужен указатель с подсчётом ссылок, который добавляет оверхед.
Что, с GC у вас ресурсы утегать не будут? Будут, ещё как будут, если вы запутаетесь в том кто и когда ими владеет.
Будут, но достаточно редко.
Иначе бы подобные ужасы были бы не нужны.
Эти ужасы только в узком слое интеропа с нативной библиотекой UI.
Какое, блин, достижение. А в цифрах — не, не покажите? Что именно вам это даёт? И как часто? С точки зрения конечного пользователя, пожалуйста.
Даёт лучшее попадание данных в кэш. Это, конечно, теоретически, а практически — надо смотреть конкретные ситуации. Мы тут вообще-то холиварим в комментах, а не ведём серьёзную научную дискуссию, поэтому ссылок на конкретные исследования не будет. Могу лишь предложить поделиться ссылкой, которая опровергает мой тезис, т.е. показывает конкретные бенчмарки, где существенного прироста производительности из-за локальности данных, обеспеченных уплотняющим GC, не обнаружено (по сравнению с каким-нибудь dlmalloc).
Всё как раз наборот. Иначе вот этого бы не было. Поверьте — у Apple есть много недостатков, но умения создать красивые, приятные в работе, программы — у них не отнять. И вот для них — GC противопоказан.
Вот это как раз весьма и весьма спорное утверждение. Я так понимаю, вопрос memory management решался ещё во времена objective C, который является по сути макронадстройкой над C, т.е. требуется поддерживать семантику C, которая не предполагает наличие специальным образом сделанного рантайма. Отсюда, единственным возможным выбором для Objective C является консервативный GC, который, как известно, не умеет инкрементальной и параллельной сборки, т.е. тормозит.
Ну так это сравнение между ручным и автоматическим управлением памятью. Подсчёт ссылок — это тоже вид автоматического управления памятью. И с ним у них был бы подобный оверхед по памяти. И вызван он был не GC, а тем, как представлены строки в CLR. А мой вопрос стоял не относительно памяти, а относительно влияния трассирующего уплотняющего GC на (пространственную) локальность, и как следствие — на производительность.
думать, кто каким объектом владеетВы хотите сказать что для языков с GC над этим думать не нужно? А для чего тогда целые библиотеки подобные Guice создают? И в чём их отличие от пресловутых «арен» (ну, кроме того, что выключить GC всё равно нельзя)?
Мы тут вообще-то холиварим в комментах, а не ведём серьёзную научную дискуссию, поэтому ссылок на конкретные исследования не будет.А тогда о чём мы вообще спорим?
Отсюда, единственным возможным выбором для Objective C является консервативный GC, который, как известно, не умеет инкрементальной и параллельной сборки, т.е. тормозит.О как. То есть для того, чтобы GC «проявил себя» нужно отказаться от использования наработанных библиотек, инструментов и прочего и, грубо говоря, начать жизнь «с чистого листа». Не много ли на себя берёт вспомогательный, по сути, инструмент?
Вы хотите сказать что для языков с GC над этим думать не нужно? А для чего тогда целые библиотеки подобные Guice создают?
Ну это вообще никак не относится к управлению ресурсами. Это DI-контейнер, нужный для облегчения реализации паттерна IoC, а уж зачем он — это вопрос архитектурный (позволяет грамотнее распределить отвественность между компонентами приложения), и никак к управлению памятью не относится.
А тогда о чём мы вообще спорим?
Ну я где-то читал (точно не помню, но по-моему, это была последняя редакция dragon book), что уплотняющий GC даёт лучшую локальность, чем компенсируется его оверхед. Сейчас конкретных ссылок на конкретные исследования дать не могу.
О как. То есть для того, чтобы GC «проявил себя» нужно отказаться от использования наработанных библиотек, инструментов и прочего и, грубо говоря, начать жизнь «с чистого листа».
Это так для legacy-мира. Но тем же Java и JS по 20 лет, .NET — 15 лет. Для них за это время написана целая куча библиотек, инструментов и "прочего". Опять же, есть средства интеропа нативных библиотек с управляемыми рантаймами. И да, разработчики обёрток, которые для managed-рантаймов заворачивают библиотеки, должны думать о явном освобождении ресурсов. Но 1) разработчики приложений об этом уже не думают 2) постепенно старые нативные библиотеки переписывают под новый рантайм.
никак к управлению памятью не относитсяА почему, собственно? Фактически это — те самые арены, которые так не любят некоторые. Только они существуют «в стороне» — и в результате в добавление к ним есть ещё и отдельно живущий (и отдельно жрущий ресурсы) GC.
постепенно старые нативные библиотеки переписывают под новый рантаймУже нет. Одно время, когда маркетинг заменил людям разум — в это верили. Но в последнее время — от этого отошли. Есть всякие разные PHP/Python/Ruby и прочее, где о скорости, в общем, не думают. И есть старые добрые нативные библиотеки на C/C++ (может со временем Rust подтянется, хотя пока рано говорить об этом).
Многолетний многомиллиардный эксперимент с Java/.NET — в общем и целом, провалился. Хотя да, последствия мы будем ещё очень долго расхлёбывать…
А почему, собственно? Фактически это — те самые арены, которые так не любят некоторые.
Многолетний многомиллиардный эксперимент с Java/.NET — в общем и целом, провалился.
Пожалуйста, не пишите глупости, не позорьтесь, если не разбираетесь в предметной области.
Я что-то пропустил? о_0
Да, упустили.
Дотнет провалился?Провалился не дотнет. Провалилась стретигия, построенная вокруг него.
Про это писали давно, но есть ещё куча разработчков, которые не понимают, что они живут «внутри пузыря».
Java (и .NET) были задуманы как способ сделать «новый мир», куда постепенно перекочуют все разработчики и, разумеется, тот, кто будет его контролировать — будет контролировать всю индустрию. Сетевой компьютер и Singularity — были очередными изданиями мечты о Lisp-машине.
Вот в этом утопическом мире — всё срастается. Когда у вас один рантайм, когда вам ничего не нужно «прогревать» — да, тогда все эти навороты с байткодом и прочим, возможно, оказываются небесполезными.
Туда были влиты буквально миллиарды, но… не вышел каменный цветок. Когда одна компания надорвалась и обанкрутилась, а другая — тихо озакрыла свой проект, то дальше — пришлось как-то те чудеса, которые были сделаны в результате этой попытки как-то утилизовать.
Так что и Java и .NET — будут ещё долго с нами. Десятилетия. Но — как памятник о неудавшейся попытке и как вечные пожиратели ресурсов.
Ибо мир — остался прежним. С операционками с виртуальной памятью и нативным кодом, многими процессами и контейнерами и т.д. и т.п. А утопия — так и осталась утопией.
А потому — потихоньку эйфорию вокрут .NET и Java сворачивают. Всё больше проектов используют нативный код и всякие pyhton/lua/etc для «склейки». А обломки мечты — жрут ресурсы на наших компьютерах и телефонах.Такой себе горатнный нерв в наших компьютерах.
Я уж молчу про то, сколько в последнее время тенденций пихать JS во все. Победы машинных языков пока не видно, все ниши затолпили в лучшем случай байткод-языки, а в худшем — скриптовые, все эти питоны/JS/Lua/…
Вопрос — наличие JITНет — это как раз не самое главное. Главное — можно ли их легко сопрягать с другими языками в одном процессе. Java и C# для этого в принципе не предназначены (интересно что когда-то Microsoft это как раз очень хорошо понимал: вспомните J/Direct… но потом эйфория архитекторов победила). Хотя, в конечном итоге, умельцы даже заставляют их дружить вместе в одном процессе — но это всё криво, сложно и достаточно «дорого» с точки зрения расходов ресурсов.
Python или Lua же — изначально предполагают, что они — всего лишь вспомогательное средство, а не «основа основ» — но это же обозначает, что весь пафос про GC и прочее — их не касается: их задача — не пытаться построить «новый мир», а всего лишь облегчить работу с теми частями программы, которые на время работы не сильно влияют. Беда начинается когда кто-то на них тяжёлые вычисления начинает делать…
Что до пафоса и великой идеи… Ведь если забыть про это всё, разница не так и велика. Вокруг сложилась тяжелая экосистема, нет хороших средств линковки с C. Но есть же встраиваемая Java, вполне взаимодействовашая с native библиотеками. В общем это воля архитекторов и лидеров сообществ идти в этом направлении. Но в параллельном мире возможен и другой сценарий.
Еще одна оговорка — для обвязки .net и java языки не очень удобны в роли обвязки.
Но в итоге, воможно, на Android так и получится — обвязка на java, а ядро на native.
То-то .Net Core один из самых востребованных репозиториев на гитхабе, нугет-пакеты из которого за жалкие месяцы скачало больше 4 миллионов разработчиков, а на дотнете построенно куча энтерпрайза, включая самый популярный программистский сайт.И? Похожие слова можно было 20 лет назад сказать про Visual Basic. Половина всех людей, которые считали себя программистами писали на нём разнообразные поделия.
Я уж молчу про то, сколько в последнее время тенденций пихать JS во все.И это тоже пройдёт. Просто долгое время (до появляения Apple AppStore и Google Play) единственным простым способом «донести» приложение до пользователя был web. Соответственно — выросла куча программистов вот под это извращение человеческого ума.
Победы машинных языков пока не видно, все ниши затолпили в лучшем случай байткод-языки, а в худшем — скриптовые, все эти питоны/JS/Lua/…Кто говорит про победу машинных языков? «Программистов» на скриптовых языках всегда было больше, чем «настоящих».
Просто всем эти создателям разных примочек под emacs не приходило в голову гордо писать в CV, что они — типа, тоже Software Enginer'ы. Слава богу сейчас их вынесли в отдельюную категорию (Application Engineer), что позволит со временем путаницу разгрести.
Умерла идея все переписать на «правильный» язык и всю систему под него заточить. Уж сколько таких попыток было и сколько их было похоронено — не перечесть. Кроме пресловутых Lisp-машин были и iAPX 432 (с аппаратной поддержкой GC, ура!) и много чего подобного. Ничего не прижилось и никогда не приживётся. Потому что на вопрос «а что делать с уже имеющимися горами ПО» ответа не даёт.
А скриптовые языки… это всего лишь скриптовые языки — они не пытаются делать вид, что они — это целый «новый» мир, а всё — остальное это всего лишь «legacy».
И это только экосистема Lisp. А есть ещё экосистема ML. Тоже с довольно интересной историей и своими текущими успехами, в том числе, в высокопроизводительных системах. Вот Вы когда заходите на https://mirage.io/, почему, как Вам кажется, оно тормозит? А вот и нет. Потому что они стартуют виртуальную машину с runtime ML внутри под конкретно Вашу сессию.
И есть ещё экосистема Haskell. Там тоже интересно.
Это я всё к чему? К тому, что идея языковой операционной среды жизнеспособна. Тем более, в наше время. Никому не интересно, C++ в приложении поверх Linux, или же Lisp на голом железе, главное, чтобы на JSON и HTTP умел общаться с окружающим миром.
Ну, то есть, скорее всего, ждёт нас эпоха мультикультурализма в плане языков программирования. Будут экосистемы с разными базовыми языками (тут вот, например, GNU решила Guile Sheme допилить до VM и реализовать поверх неё Python, JS, Ruby и Lua), ну, а программист уже будет просто выбирать в какой экосистеме ему комфортнее.
Экосистема С/С++ вряд ли куда-то пропадёт с этого праздника жизни и разнообразия, но возвращение Lisp-машин, или появление униядер ML, или мощных runtime-ов Go вполне, мне кажется, имеет смысл приветствовать.
Повторюсь, людям это интересно, и это не давление сверху со стороны SUN или Microsoft, просто людям так эффективнее работается. Хорошо же.
А чем Вам так не нравятся Lisp-машины?Они просто наиболее известны. А так — да, попыток было много.
К тому, что идея языковой операционной среды жизнеспособна.Пока что все попытки кончались тем, чем и должны были кончаться — несколько лет шумихи, пока вкладываются деньги, потом — возврат на С, Fortran и прочее.
тут вот, например, GNU решила Guile Sheme допилить до VM и реализовать поверх неё Python, JS, Ruby и LuaАга. И продемонстрировала proof-of-concept с поддержкой scheme и tcl в 1995 году. На календарь давно смотрели?
ну, а программист уже будет просто выбирать в какой экосистеме ему комфортнееОх уж эти сказки, ух уж эти сказочники. В том-то и дело, что эти попытки — «ходят по кругу»: сначала за короткое время делается proof-of-concept, дальше с ним носятся, как с писанной торбой, потом — туда вбухивается куча денег (иногда — миллионы, иногда — миллиарды, как повезёт), а потом… финансирование кончается.
И да — побочные эффекты часто двигают индустрию вперёд. А вот «философский камень» всё как-то не вырисоывается… Такая «современная алхимия»…
Повторюсь, людям это интересно, и это не давление сверху со стороны SUN или Microsoft, просто людям так эффективнее работается. Хорошо же.Чего хорошего в том, что люди пишут 100 парсеров JSON'а и 500 http-серверов? Хорошо хоть TCP/IP стек системный используют.
Лучше бы вместо того, чтобы разрабатывать 100500 изолированных миров подумали бы о том как делать систему в которой можно программировать на разных языках — но почему-то все попытки так сделать приводят только к ещё одному монстру, который пытается в себя втянуть весь мир…
Они просто наиболее известны. А так — да, попыток было много.
Так в том-то и дело, что Lisp-машины не были «попыткой». Это было развитое направление в индустрии. И развивались они быстрее, чем UNIX и Си. И успехов там было много. Люди вот об этом помнят. Поэтому и стремятся повторить успех. Тем более, на новом уровне производительности и технологий можно более интересные вещи делать.
Ага. И продемонстрировала proof-of-concept с поддержкой scheme и tcl в 1995 году. На календарь давно смотрели?
И что? Non-profit же. Хотят — делают, хотят — не делают. Guile вообще долго не развивался, но пару лет назад за него снова взялись.
И да — побочные эффекты часто двигают индустрию вперёд. А вот «философский камень» всё как-то не вырисоывается… Такая «современная алхимия»…
Да никто там не ищет «философского камня». Просто есть проблемы, есть подходы к их решениям, есть люди, которые верят в эти подходы и работают над ними. Си/Си++ же тоже не идеальны. Да, код быстрый, но работать с динамическими данными тяжело. Если на Java можно написать WebSphere, а на Erlang ту же Riak, то можно ли это сделать на Си++? Ну, не знаю. Никто почему-то не сделал. Почему?
Чего хорошего в том, что люди пишут 100 парсеров JSON'а и 500 http-серверов? Хорошо хоть TCP/IP стек системный используют.
Лучше бы вместо того, чтобы разрабатывать 100500 изолированных миров подумали бы о том как делать систему в которой можно программировать на разных языках — но почему-то все попытки так сделать приводят только к ещё одному монстру, который пытается в себя втянуть весь мир…
А люди и так напишут 100 парсеров JSON-а, даже если у них будет один язык программирования. А потом напишут ещё парсеры для других языков программирования. И так далее. Ну, и, люди любят вообще-то искать свою идентичность в каких-нибудь малых группах. Мы вообще не приспособлены ощущать себя хорошо в многомиллионных однообразных коллективах. Поэтому вот так вот.
Но я не понимаю, а чего Вы так переживаете? Вряд ли экосистема UNIX/Си в ближайшее время куда-нибудь пропадёт. Работы в ней для всех хватит. Маловероятно, что Intel, Apple или Google накроются медным тазом и GCC или LLVM останутся без финансирования и остановятся в развитии.
Поэтому и стремятся повторить успех.Нельзя дважды войти в одну и ту же реку. Вопрос насчёт «успеха» — тоже отдельный, но даже если признать что он таки был — время несовместимых решений ушло.
Если на Java можно написать WebSphere, а на Erlang ту же Riak, то можно ли это сделать на Си++? Ну, не знаю. Никто почему-то не сделал. Почему?А что именно вы понимаете под «WebSphere под Си++»? Чем он будет отличаться от Docker?
Но я не понимаю, а чего Вы так переживаете?Потому что наследием всего этого является совершенно нерациональное расходование ресурсов. Что особенно заметно на Android'е, но и не только на нём (и было бы ещё заметенее если бы в iOS разработчики не всовывали всякими правдами неправдами всяких монстров типа Mono).
Но почему нерациональное?Потому что лишняя работа ещё никогда и никем забесплатно не делалась.
Мотивация у Java — это более рациональное использование ресурсов: зачем проверять каждый доступ в память, если можно гарантировать, что они всегда будут верными?Да, идея была красивой. Но… не работает. Без аппаратной поддержки — не работает. Вот, собственно, официальная капитуляция.
Java вообще и сборка мусора в частности — это прекрасная иллюстрация известного принципа: на всякий сложный вопрос имеется ответ – ясный, простой и ошибочный.
И дело даже не в чайниках, а в том, что они посчитали: их сервера под нагрузкой тратят 30% времени на обслуживание виртуальной памяти.Ну да. А сколько они тратят на обслуживание двух видов виртуальной памяти друг над другом??
В том-то и дело, что это было решение не той задачи, не там и не для того. В узких нишах — да, это решение применимо (собственно меня удивляет что вы этого идейного потомка Лисп-машин на божий свет не вытащили), но как универсальная платформа — оно не годится. Просто потому что проигрывает в скорости другим подходам.
P.S. И тут ещё нужно учесть что любое «узкое решение» со временем стремится стать «широким». На тех же AS/400 сейчас часто гоняется какой-нибудь PHP, что в результате стоит дороже, чем гонять его на обычных серверах — но если вы уже завязались на AS/400, то вам приходится жрать этот кактус…
Да, идея была красивой. Но… не работает. Без аппаратной поддержки — не работает. Вот, собственно, официальная капитуляция.
А в чём Вы видите факт капитуляции? Ну да, на поддержку Applet-ов забивают постепенно, потому что есть JavaScript. Вполне естественно, об этому говорили ещё тогда, когда V8 только появился.
Java вообще и сборка мусора в частности — это прекрасная иллюстрация известного принципа: на всякий сложный вопрос имеется ответ – ясный, простой и ошибочный.
Сборка мусора никогда не была ясным и простым ответом на проблему. Ясный и простой ответ — это просто запретить свободную динамическую память, как в Fortran. Всегда было понятно, что сборка мусора — штука сложная и требует много усилий для реализации. Но так же было понятно, что во многих сценариях она необходима.
Тут же дело какое. Сборка мусора — это не просто способ управления памятью, это, действительно, техника которая влияет на всю систему конкретного языка. Если сборки мусора нет, то библиотеки надо писать одним способом, а если есть, то можно писать другим. И со сборкой мусора библиотеки могут быть гораздо более гибкими. А это тоже важно, если программист может не тратить 50% своего времени на продумывание схемы управления ресурсами, а сразу реализовывать алгоритм.
На Си++ тоже, наверное, можно сразу сесть за реализацию, ничего не продумывая в плане потока ресурсов. Но лично мой опыт показывает, что потом 10 раз придётся всё переписывать.
Скорость разработки тоже штука важная. И это было понятно ещё во времена Алгол-68.
Ну да. А сколько они тратят на обслуживание двух видов виртуальной памяти друг над другом??
В смысле? В безопасных языках нет виртуальной памяти. На том и стоят. А когда они работают с виртуальной памятью, то продвинутые системы типа .Net или Java пытаются её задействовать в свою пользу. Например, используют cow-отображения страниц при копировании больших объектов. Можно так сделать на Си++? Можно. Но кто же так будет делать? На Си++ скорее всего, человек просто наплодит адову схему из перекрёстных ссылок.
И тут возникает вопрос, а что считать стоимостью? Ведь, код пишут люди. Люди пишут через пень-колоду. И не факт, что та схема управления ресурсами, которую написал Василий, будет эффективнее, чем сборка мусора. Программы-то сложные.
Кроме того, никто не отменял техники оптимизации. Можно оптимизировать код со знанием того, что он будет работать со сборкой мусора. Пишут же люди довольно быстрые игры на Java. Просто выделяют несколько больших массивов для хранения всего необходимого и сборка мусора их почти не касается.
Просто потому что проигрывает в скорости другим подходам.
Нет объективных данных, что проигрывает. Проблема со сборкой мусора не в проигрыше вообще по скорости, а в том, что есть проблема непредсказуемых задержек. В среднем, в пакетных режимах, сборка мусора забирает до 5% времени (в равнении с виртуальной памятью — копейки), в зависимости от задачи.
Проблема именно с непредсказуемыми задержками. Но опять же. Когда всё живёт поверх виртуальной памяти, то никаких гарантий на задержки тоже нет. TLB будет вносить неопределённости, операционка будет дефрагментацией заниматься, cow-процессы будут происходить.
Автоматически от использования Си++ проблема не исчезнет. Для гарантии задержек нужно будет специальным образом писать код и специальным образом резервировать ресурсы. Но в точности такое же можно делать и в системах со сборкой мусора. Там есть технологии realtime-пулов памяти и всего такого прочего.
Гарантированных времён реакции системы можно добится и с одной техникой, и с другой. В конце концов всё упирается в умения и навыки программиста. И это очень важный экономический фактор.
Ну, а здесь, как ни крути, Си++ Java совсем не конкурент. Даже на Haskell писать проще, чем на Си++. Потому что на Си++ элементарно отстреливаешь себе все конечности, и даже не знаешь, что именно оказывается отстреленным. Отладка больших Си++ программ — вот истинный источник боли и унижения в современном мире.
А в чём Вы видите факт капитуляции?Подписанные апплеты не используют механизмы Java для обеспечения безопасности. В частности они могут загружать нативные библиотеки. Рассказать куда можно засунуть все ваши проверки если в Java-машину загружена нативная библиотека через JNI или сами догадаетесь?
Но так же было понятно, что во многих сценариях она необходима.Совершенно непонятно. Чуть ли не основной повод для сборки мусора — это усложнение интерфейсов. Что такого в интерфейсах появилось со времён какого-нибудь Visual Studio 6, что вдруг потребовало сборки мусора?
В смысле? В безопасных языках нет виртуальной памяти.Так в том-то и дело, что нет безопасных языков в природе почти. Просто… нет. История про Java — описана выше. Вот вам про python.
То есть сдалать-то безопасный язык можно… а потом добавляются фичи, ещё фичи, примочки, хотелочки… и оп-па: язык у вас, оказывается — небезопасный. Его, оказывается, нужно на уровне операционной системы ограничивать. А тогда, извините, за что мы, собственно, платим?
И не факт, что та схема управления ресурсами, которую написал Василий, будет эффективнее, чем сборка мусора.Факт. Причём достаточно очевидный факт.
Программы-то сложные.А вот тут — в точку. Программа — это газ. И её сложность — тоже. Вася не сможет реализовать менее эффективную схему управления/ ресурсами на языке без GC. Просто не сможет. Его программа — будет падать и всё.
Вопрос не стоит как «а будут ли лучше программы, написанные на языке без GC», а как «компенсирует ли ускорение разработки ухудшение качества программа вызванное использованием GC?».
Пишут же люди довольно быстрые игры на Java. Просто выделяют несколько больших массивов для хранения всего необходимого и сборка мусора их почти не касается.Действительно: а чёб нам не ввести подсистему, которая должна нам всё «улучшить», а потом начать её героически преодолевать? И всё равно GC нет-нет да отжирает свои ресурсы, так как отключить его полностью в Java нельзя.
В среднем, в пакетных режимах, сборка мусора забирает до 5% времени (в равнении с виртуальной памятью — копейки), в зависимости от задачи.В том-то и дело, что не «в равнении», а в добавление! «В равнении» — это в очень ограниченных узкоспециализированных системах на ограниченном промежутке времени.
Отладка больших Си++ программ — вот истинный источник боли и унижения в современном мире.А это уж «кто на что учился», извините. Грамотно написанная программа никакой особой боли не вызывает, не больше чем программа на Java. А неграмотно — тут да. Программа на Java, написанная кривыми руками обеспечит целое пополение «условных индусов» работой на годы вперёд. Подобная же программа на C++ — просто не заработает. Но является ли это недостатоком Java и проблемой C++? Зависит от ваших задач…
Так в том-то и дело, что нет безопасных языков в природе почти. Просто… нет. История про Java — описана выше. Вот вам про python.
То есть сдалать-то безопасный язык можно… а потом добавляются фичи, ещё фичи, примочки, хотелочки… и оп-па: язык у вас, оказывается — небезопасный. Его, оказывается, нужно на уровне операционной системы ограничивать. А тогда, извините, за что мы, собственно, платим?
Безопасные языки есть. И есть безопасные системы. Я уже приводил пример MirageOS. Unsafe-режимы нужны, в основном, именно для того, чтобы вписываться в существующие native-экосистемы или использовать native-библиотеки, потому что родных нет. Если такой необходимости нет, то можно написать операционку типа House, и жить целиком на Haskell, на одной дискете и не испытывать проблем с производительностью.
Native — это не технологическая необходимость, а экономическая. Я уже говорил, что да, действительно, это важный фактор. И моя точка зрения заключается в том, что именно он самый важный фактор в устойчивости текущих основанных на Си/Си++ программных экосистем. Просто кода понаписано столько, что его уже не перенести никуда за разумные деньги. Не в скорости тут дело совсем. Уже довольно долго существуют безопасные системы, которые по скорости исполняемого кода уделывают Си/Си++. ATS, например.
А вот тут — в точку. Программа — это газ. И её сложность — тоже. Вася не сможет реализовать менее эффективную схему управления/ ресурсами на языке без GC. Просто не сможет. Его программа — будет падать и всё.
Да ладно!? Такое ощущение, что Вы никогда не сталкивались с говнокодом. У меня был случай, когда нам пришлось искать баг в программе, в которой каждый день утекал один мегабайт данных. Мы нашли места утечек при помощи Valgrind. Мы даже поняли, почему так происходит. Но исправить ничего у нас не получилось, потому что мы не смогли переписать код, там сотни тысяч строк кода и наивные попытки просто его роняли. Можно было бы зарефакторить всё, но никто бы нам этого не оплатил. В итоге, заказчик просто каждый день стал перезапускать приложение. Вот Вам и эффективность.
При этом, программа вполне себе работала два месяца подряд, потом падала, потом снова работала.
И я сомневаюсь, что это нетипичная ситуация.
Действительно: а чёб нам не ввести подсистему, которая должна нам всё «улучшить», а потом начать её героически преодолевать? И всё равно GC нет-нет да отжирает свои ресурсы, так как отключить его полностью в Java нельзя.
Да никто и никогда не считал GC «улучшением». GC — это необходимое зло в безопасных системах. И с ним точно так же, как скажем, с количеством системных вызовов в Си-программах, или с количеством синхронизаций в параллельных программах яростно сражаются, пытаясь всячески развить и компиляторы, чтобы точно вычислять регионы использования ресурсов, и придумать способы эффективного программирования.
Борьба идёт именно за безопасность, а не за сборку мусора. Сможете предложить, как делать безопасный код с ручным управлением памятью — сообщество возрадуется. Но, к сожалению, это принципиально невозможно.
А это уж «кто на что учился», извините. Грамотно написанная программа никакой особой боли не вызывает, не больше чем программа на Java. А неграмотно — тут да. Программа на Java, написанная кривыми руками обеспечит целое пополение «условных индусов» работой на годы вперёд. Подобная же программа на C++ — просто не заработает. Но является ли это недостатоком Java и проблемой C++? Зависит от ваших задач…
Ещё как заработает! Нет, ну в самом деле. Вон в соседней статье обсуждают косяки в коде MySQL.
Кстати. Вы сужаете тему принудительно к Java против C++. Java, действительно, не является идеальным языком с точки зрения надёжности, безопасности и технологической продвинутости. Тут бы со Scala надо сравнивать.
Но есть и другие языки, в которых всё намного лучше. А сама технология безопасных языков и language-level os развивается. Пока в академическом сообществе. Может быть, она там останется навсегда. А, может быть, и не останется. Уж слишком хорошо иногда получается. Снова упомяну ATS и Arrp.
Сборка же мусора сама по себе не мешает добиваться высокой производительности и спускаться на уровень ассемблера. Примером может служить GOAL (вообще Lisp), которым до сих пор пользуются в Naughty Dog для программирования игр.
Советую вам ради интереса посмотреть на ICFP-2015 и ICFP-2016. Там довольно большая движуха именно на эту тему. Очень много объективно крутых проектов.
Они пока ещё не вписаны в общую экосистему, но по отдельности впечатляют. Arrp какой-нибудь с глобальной оптимизацией и вращениями вычислений над многомерными массивами, и автоматическим параллелизмом (TensorFlow тихонько завидует в сторонке). Или тот же Ur/Web.
Сейчас уровней виртуализации очень много. Чрезмерно. Все с этим пытаются бороться. Не факт, что выйдет нечто годное. Но не факт, что и не выйдет.
Не очевидно, кстати, что SUN погорела именно из-за Java. У них много косяков в стратегии было.
Не очевидно, кстати, что SUN погорела именно из-за Java.Никакого отношения к проблемам SUN'а Java не имеет. Проблема SUN'а была в том, что сделать «новый мир» не удалось, а на попопытку его сотворить ушли все наличные ресурсы.
В своё время S/360 была похожим проектом — но там дело выгорело по двум причинам:
1. У IBM был больше «запас прочности».
2. Они изначально сделали ставку на железо и очень жёстко пресекали всех желающих выпускать совместимые модели.
В результате SUN — со своим «новым миром» кончился, а IBM железяки выпускает и продаёт до сих пор.
Всё как раз наборот. Иначе вот этого бы не было. Поверьте — у Apple есть много недостатков, но умения создать красивые, приятные в работе, программы — у них не отнять. И вот для них — GC противопоказан.
У Apple как раз GC и был. Потом уже начали съезжать на другое. Как раз для UI GC отлично работает, ибо пауз в работе полным полно, которые никто не заметит. Да и GC нынче в фоне работают параллельно коду. А вот какой-нить серверный код высоконагруженный требует довольно много от GC, ибо там паузы будут очень сильно заметны.
У Apple как раз GC и был.Была экспериментальная поддержка — только в MacOS. В iOS — не было никогда и даже на десктопе эксперимент был признан неудачным.
Как раз для UI GC отлично работает, ибо пауз в работе полным полно, которые никто не заметит.Только если у вас Ынтырпрайз приложение, за использование которого людям деньги платят. В противном случае — вам нужно реагировать за пресловутые 16 миллисекунд.
А вот какой-нить серверный код высоконагруженный требует довольно много от GC, ибо там паузы будут очень сильно заметны.Вы это серьёзно? Много вы серверных приложений видели, гарантированно дающих ответ за 16 миллисекунд? Разве что на бирже…
Только если у вас Ынтырпрайз приложение, за использование которого людям деньги платят. В противном случае — вам нужно реагировать за пресловутые 16 миллисекунд.
И с GC нормальным оно будет прекрасно реагировать, потому что stop-the-world практически не будет происходит. Все будет в фоне. Такое ощущение, что у вас GC на несколько секунд всю программу вешает. Может у Apple оно так и было, но у нормальных GC реализаций с этим все в полном порядке.
Вы это серьёзно? Много вы серверных приложений видели, гарантированно дающих ответ за 16 миллисекунд? Разве что на бирже…
Серьезно настолько, что даже в Go над этим до сих пор трудятся и правят перодически всплывающие хитрые кейсы, когда гарантии задержек уплывают и это сразу фиксят. Чрезвычайно важны минимальные задержки и их постоянство. Это вам не UI, где пока человек моргнет, уже весь мусор собран будет.
Может у Apple оно так и было, но у нормальных GC реализаций с этим все в полном порядке....
Серьезно настолько, что даже в Go над этим до сих пор трудятся и правят перодически всплывающие хитрые кейсы, когда гарантии задержек уплывают и это сразу фиксят.Так «всё в полном порядке» или «над этим до сих пор трудятся»?
«Старую песню о главном» про то, что вот ещё чуть-чуть и GC перестанет быть проблемой — я слышу сколько я программистом работаю, уже не один десяток лет. А воз и ныне там.
И при уплотнении тоже никакого оверхеда?
При уплотнении есть оверхед. Другое дело, что GC не обязательно должен быть уплотняющим. Но уж так сложилось, что для передовых рантаймов пишут уплотняющие GC, наверное, практика показала, что они эффективнее. Потому что так аллокация сильно дешевле (по сути — обычный инкремент), и потому что расходы на уплотнение компенсируются выигрышами от пространственной локальности.
Никаких локов, ничего, не нужно оно там. GC правда может эффективнее?
Кстати, я где-то видел презентацию, где в Graal добавили region-based memory management, и не получили ощутимого прироста производительности. GC не может эффективнее, но может в ряде случаев приближаться по эффективности. По крайней мере, аллокация и освобождение столь же дешёвые, минус расходы на обход графа объектов.
Так давайте определимся, уплотняющий GC или нет. А то получается, что преимущества приводятся для их объединения.
В современных рантаймах GC уплотняющие, и это подаётся как преимущество, а не как недостаток, вопреки тому, что уплотнение даёт оверхед.
А откуда вообще следует, что она, ну, есть? Ведь для пространственной локальности необходимо, чтобы, условно, следующий объект в памяти, к которому вы обращаетесь, лежал в вашем кешлайне. Как это связано с компактифицирующим GC?
Собственно, причины две. Во-первых, в survival space объекты будут лежать кучно, и они могут взять и влезть в кэш. Во-вторых, при выделении памяти в eden space она будет всегда выделяться строго последовательно, а не в дырках.
С generational GC, да, связано, но не с компактифицирующим.
А поколения тут при чём? Поколения нужны, чтобы уменьшить паузы и увеличить пропускную способность за счёт обхода только подмножества графа. Или я что-то не понимаю?
В вышеупомянутом подходе их вообще нет.
Это понятно, что в определённых ситуациях можно вручную управлять памятью эффективнее, чем GC. Но во-первых, это отнюдь не те пресловутые 95% ПО, а во-вторых, это не всегда даёт достаточный выигрыш, чтобы оправдать увеличение стоимости разработки.
Так, иногда и компиляторы идут лесом и код, написанный вручную на ассемблере, оказывается быстрее. Например, интерпретатор Java-байткода за счёт грамотного распределения регистров аж в 2 раза быстрее работает, если его написать на ассемблере. Но в большинстве случаев компилятор тупо умнее программиста.
выделял где-то с десяток мегабайт при инициализации, сдвигал указатель вперёд при выделении памяти, ничего не делал при освобождении, и прибивал всю память одним махом при завершении обрабокти запроса.
Я вас поздравляю: вы реализовали eden область java-вского хипа.
поэтому,
GC правда может эффективнее?
нет, он просто уже делает из коробки то, что вам пришлось изобретать. «Всяк велосипедостроитель свой велик хвалит»
И он автоматом понимает, что на каждый запрос достаточно иметь свою область в десяток мегабайт?
это несущественная особенность реализации. А я говорю о принципе. Понятно, что оно там написано не точно так же как у вас. Eden у него там фиксированного размера, можно ключиками запуска регулировать.
в каждый момент обрабатывается одним тредом, то блокировки не нужны совсем?
Да, на каждый поток своя область памяти, поэтому создать и бросить объект — так же быстро, как и у вас. А если объект выживает, и ссылка на него пошла по потокам(или даже не по потокам) — то потом gc переносит его в другую область.
И что при завершении запроса можно вообще всю память грохнуть, не проходя по графу объектов?
да, насколько понимаю. Тут понятно, что как-то выжившие объекты выдергиваются и переносятся в другую область. Но скорей всего, это происходит не проходом «в лоб», в том понимании, которое вы подразумевали. Процесс этот достаточно быстр. И в G1, насколько понимаю, может быть просто выбрана другая область, если в данной что-то пооставалось. Но тут инфа не 100%. Как оно там точно сделано в деталях — не знаю.
если запрос всё ещё обрабатывается, то память трогать не надо, что бы в других запросах не происходило?
Если обработка другим потоком — то может и не затронуть, а если этим же потоком, то объекты перекочуют в другую область памяти, где уплотнение происходит другим алгоритмом.
И ещё, небось, никакого оверхеда, кроме действительно той памяти, что была выделена, нет?
тут смотря как считать и что считать оверхедом. Однозначно на этот вопрос ответить невозможно. Тут так же надо понимать, что когда ты делаешь malloc() — то есть тоже некоторый «оверхед» который нужен для free. И поскольку алгоритм eden нельзя использовать для всего — оверхедом тоже можно принебрегать только в узком круге задач. В java каждый объект наследуется от Object, а он в зависимости от jvm и архитектуры занимает от 12 байт (не считая всяких внутренних классов, которые заоптимайзены и могут занимать меньше). И в этих 12 байт, насколько понимаю — значительная часть того же оверхеда, который в сишном хипе используется для free. Поэтому говорить, мол «в java на каждый обьект накладные расходы 12 байт, а в сишном хипе на каждый malloc ноль накладных» — некорректно.
Разумеется, ваш специализированный хип будет более оптимальным в этом смысле.
А фактически — у вас свой велосипед, который является обрезаной и доработаной для вашей задачи версией существующего.
Если говорить принципиально — оно там одинаковое, различие только в деталях, которые в той или иной задаче дадут небольшой выигрыш или проигрыш.
Грааль сборщика мусора в том, что он должен происходить на уровне железа.
1. Чем сложнее проекты и алгоритмы, тем потребность в сборке мусора выше. Обычно, в сложном коде приходится вводить какую-нибудь сборку мусора. Например, выдумывать арены.
2. Rust проблему решает, но за счёт существенного увеличения сложности программирования. Первая версия кода пишется почти без проблем. Но дальнейшее перепроектирование и переписывание алгоритмов управления ресурсами даются непросто. Да и потом, нормальный статический анализ кода может все эти эффекты просто вычислить.
3. Безопасность. Это тоже очень важно. Одновременно безопасности и достаточного уровня сложности без сборки мусора не достичь. При этом, в современных системах, даже если программисту кажется, что в его программах нет сборки мусора, на деле она есть на уровне операционной системы. Кроме того, чтобы обеспечивать безопасность и гибкое управление ресурсами приходится работать через виртуальную память, а это накладные расходы на каждую операцию чтения или записи. Повторюсь, на каждую операцию доступа в память накладные расходы 20%.
Поэтому сравнение языков со сборкой мусора и без сборки несколько нечестное в современной экосистеме. Языки со сборкой мусора работают поверх другой системы со сборкой мусора и виртуализацией, то есть, в них
задача решается двукратно. И задержки вполне могут быть результатом работы подсистемы виртуальной памяти, а не самого алгоритма сборки мусора. Тут конкретно всегда смотреть надо. Замусорить кэши трансляции до многократного падения производительности можно на любом языке программирования. Когда есть сборка мусора, автоматически, вина перекладывается на неё, но часто проблемы бывают вызваны корявыми структурами данных.
Честных сравнений я не видел. Возможно, прогресс с юниядрами (unikernel) покажет картину более отчётливо.
Довольно интересно тут пофантазировать на тему того, что где-то в недрах Google живут серверы, на которых работает только Go runtime, без прослойки обычной ОС, и за счёт этого они экономят 10% вычислительного времени.
4. Ещё одна проблема в языках программирования. Современное состояние искусства программирования подразумевает интенсивное использование указателей. С этой точки зрения Go намного лучше Java, потому что позволяет создавать массивы разнообразных структур. Меньше нагрузка и на кэши, и на сборщика мусора. В функциональных языках ситуация ещё лучше. Статический анализ убегания (escape-анализ) и оптимизации могут утрамбовывать данные для них очень плотно, даже до сворачивания динамических списков в массивы на стеке. Однократное присваивание существенно облегчает задачу.
К сожалению, пока мы не умеем писать системный код на функциональных языках. Но люди работают над этим.
5. В общем, всё непросто. Ну, и чем старше становишься, тем больше тянет на языки со сборкой мусора. Я думаю, это не от лени, а от того, что приходится решать всё более логически сложные задачи. На текущем уровне технологий, лично я стараюсь высокопроизводительный код делать максимально тупым в отношении управления ресурсами, выносить его в отдельные процессы, а управление этими тупыми процессами прописывать уже на языках со сборкой мусора. Ну, или же, если заказчик упёртый, то делать то же самое, но с аренами. А иначе сложную систему просто не сделать.
6. Будущее, скорее всего, за системами сборки, получающими информацию от статических анализаторов кода. В конце концов, всегда можно пофантазировать о сборщиках мусора, оптимизированных под семантику конкретных структур данных.
Но для того чтобы программа оставалась корректной логику ее работы все равно приходится переделывать и не немного, а очень сильно вне зависимости от того используете ли вы GC и/или статический анализатор.
Вы не верите в дальнейшее развитие Rust на этом поприще только из-за сложности разработки на нем?
По идее, Rust очень молодой язык программирования с новыми/революционными концепциями (по крайней мере, для mainstream'a). Мне кажется, со временем эти новые концепции должны вполне нормально осесть в головах у разработчик + появятся специализированные для Rust'a tool'ы для разработки. Это должно уменьшить порог входа и упрость понимание и разработку программ на Rust. Как дополнительный бонус, выполнение программы становится более детерминированным и язык провоцирует писать корректные и оптимальные в плане используемых ресурсов программы.
Вы не верите в дальнейшее развитие Rust на этом поприще только из-за сложности разработки на нем?
О! Это интересный техно-культурно-экономический вопрос. Я не знаю, но у меня есть некоторые соображения, возникшие в результате наблюдений за lambda-the-ultimate и ICFP.
Алгоритмы компиляции (а именно, вывода типов) стали экспоненциально умнее, и железо стало экспоненциально быстрее. Оно вышло на какой-то предел одноядерной производительности сейчас, но появляются облака, GPU, FPGA и прочее. И в оптимизаторах начинают применять вычислительно тяжёлые методы. Z3, например, для решения SAT. Или даже машинное обучение в некоторых пока экзотических случаях.
И это помогает. Например, llvm-souper (супер-оптимизатор для llvm) помогает разработчикам искать новые варианты оптимизации кода, до которых они сами не додумались. Потом эти методы прописывают в llvm.
Видимо, в долгосрочных планах у многих разработчиков стоит задача о переносе компиляторов в облачную инфраструктуру, где за счёт эффектов масштаба возможны новые интересные вещи. Вот есть llvm-souper, есть MirageOS от сообщества OCaml.
И эти штуки неплохо работают. Особенно SAT-решатели на задачах типизации. То есть, сейчас относительно просто по коду программы присвоить тип переменной какой-нибудь такой: int 32 бита, у которого 3-ий бит всегда 0. То, что анализатор может вытащить из программы, программист, наверное, тоже может написать явно, но ему придётся писать это слишком долго.
И вот касательно Rust. Возникает тогда вопрос: а зачем разработчику прописывать все эти ограничения на переменные, если, всё равно, придёт мощный оптимизатор и сам всё это посчитает вместе с сотней других важных параметров?
Если бы Rust появился на 10 лет раньше, он бы успел набрать критическую массу пользователей и успел бы в mainstream. А сейчас, есть у меня подозрения, что JavaScript в недалёком будущем производительностью не будет уступать C++
https://github.com/ispras/llv8 (ispras — это http://ispras.ru)
Вот и возникнет у простого программиста вопрос: а зачем учить Rust, если можно выучить JavaScript и не особо проиграть?
И вот касательно Rust. Возникает тогда вопрос: а зачем разработчику прописывать все эти ограничения на переменные, если, всё равно, придёт мощный оптимизатор и сам всё это посчитает вместе с сотней других важных параметров?
Я бы сказал — для самого разработчика. Это может не играть роли для монолитного бинарника. Но ох как важно для библиотечного кода. В том числе позволяет оптимизатору делить работу на куски поменьше. Без аннотаций придётся каждый раз делать анализ всего графа программы.
https://github.com/ispras/llv8 (ispras — это http://ispras.ru)
Это крайне интересный проект, без шуток.
Но как он отработает на "обычном" JavaScript с пачками интроспекции, манкипатчингом и другой динамикой? Как он будет жить на библиотечном коде? Проблема в динамической от природы и, скажем прямо, кривой от рождения семантике JavaScript. Даже самый умный оптимизатор будет вынужден будет думать о ситуации когда в некое под-дерево функций передадут совершенно не то, что ожидали.
А чем это лучше java'ого jit'a? Кроме того что java — это статически типизированный язык, а javascript — динамический и llv8 еще сложнее это все будет правильно выводить и делать какие-нибудь предположения для серьезной оптимизации.
Что-то мне не верится, что даже джавовые БД-шки будут в обозримом будущем конкурировать по производительности с С/С++-ными, а тем более javascript'овыми.
Кроме того, чтобы обеспечивать безопасность и гибкое управление ресурсами приходится работать через виртуальную память, а это накладные расходы на каждую операцию чтения или записи. Повторюсь, на каждую операцию доступа в память накладные расходы 20%.
WAT? Вы уверены что на каждую операцию? Что-то мне подсказывает, что если нужные записи уже в TLB, а сами данные лежат в кеше, то overhead будет намного меньше.
Я ещё могу согласиться на 20% накладных расходов в среднем (да, page walk занимает много времени, не говоря о paging fault). Но если соблюдать локальность. то накладные расходы должно быть намного меньше.
Но, я думаю, тут надо учитывать какие-нибудь экономические факторы. Singularity была бы настоящий disrupt-технологией. То есть, рынок железа существенно бы трансформировался. Может быть, поэтому решили не выпускать. А, может быть, просто Z3 был сырой, и не умел считать всё, что нужно.
Но сейчас всякая такая техника то там, то здесь вылазит. Например: Ur/Web. Штука умеет целиком про клиент-серверное приложение с базами данных доказывать, что оно корректное, вычислять регионы жизни ресурсов и обходится без сборки мусора. Скорость на уровне C++, а кода раз в 10 меньше. Плюс GADT и всё такое прочее. Минус в том, что не для каждой программы она способна построить вывод всего того, что нужно, иногда вывод отрезается по глубине рекурсии. Но автор пишет, что, для обычных программ, а не специальных контрпримеров, всё нормально.
Когда есть сборка мусора, автоматически, вина перекладывается на неё, но часто проблемы бывают вызваны корявыми структурами данных.Это спор между тупоконечниками и остроконечниками. Если у вас все структуры данных — хорошо «отстроены» и вы хорошо понимаете когда и как выделяется/освобождается память — то вам GC не нужен от слова «совсем».
А вот если код «писан индусами», не понимающими что, как и где вообще происходит (знаменитое «к пуговицам претенции есть?»), вот тогда — с GC всё будет тормозить и жрать память, как не в себя, а без GC — вообще развалится к чертям собачьим.
Так что хотя прямой связи между использользованием GC и тормозами — нет, но корелляция — почти 100%.
вы хорошо понимаете когда и как выделяется/освобождается память
Вот это не всегда возможно понять. И приходится в таких случаях писать свою версию GC. Ну да, мы это назовём частью структуры данных. Но, фактически, это будет сборщик мусора. Хочу ли я постоянно писать сборщики мусора?
Теперь уже не уверен.
А вот если код «писан индусами», не понимающими что, как и где вообще происходит (знаменитое «к пуговицам претенции есть?»), вот тогда — с GC всё будет тормозить и жрать память, как не в себя, а без GC — вообще развалится к чертям собачьим.
Так вот именно! Только проблема в том, что в 90% случаев, ты сам и являешься таким вот индусом. Потому что, срок сдачи проекта «вчера». А за другие сроки сдачи тебе не заплатят. КапитализЪм основной двигатель сборки мусора.
Поэтому я и говорю, что имеет смысл разделять код на мусорный и на ручной, который будет писаться на Си с минимумом управления ресурсами, но при этом работать быстро. А мусорный — ну фиг с ним. Главное, быстро нафигачить. К сожалению, такова реальность.
Хочу ли я постоянно писать сборщики мусора?Ну зачем же каждый раз с нуля писать? Есть же готовые библиотеки.
Теперь уже не уверен.Проблема в том, что альтернатива — это «GC как раковая опухоль». Всепроникающий монстр проникающий во всё в системе: от API до способов вызова функций и вообще всего, что есть в программе.
Поэтому я и говорю, что имеет смысл разделять код на мусорный и на ручной, который будет писаться на Си с минимумом управления ресурсами, но при этом работать быстро. А мусорный — ну фиг с ним. Главное, быстро нафигачить. К сожалению, такова реальность.Совершенно верно. И с этой реальностью я даже спорить не хочу. Если ваша задача — что-то сделать быстро (и неважно что память будет жраться «как не в себя» и другие ресурсы будут транжириться тоже) — то GC вполне себе неплохое решение.
Но почему-то апологеты GC этого признавать не хотят и пытаются делать вид, что у «всеобъемлющего GC» есть какие-то другие преимущества. Нету. Всё остальное — проблемы. А важно ли вам конкретно это достоинство или нет — действительно зависит от задачи.
Ну зачем же каждый раз с нуля писать? Есть же готовые библиотеки.
Ага. Только я боюсь библиотек, в которых есть управление памятью. Собственно, отсюда Rust и начался, потому что Mozilla задолбалась бороться с утечками. Это серьёзная проблема, к сожалению. Тут надо как-то аккуратно совместно разрабатывать и семантику языка, и методы управления памятью, и методы управления управлением памятью. Потому что realtime и сборка мусора не совместимы по определению на уровне современных технологий.
А хотелось бы. IMHO, было бы прекрасно, если бы на уровень языка получилось бы как-то аккуратно вынести то, что делает UNIX, управляя процессами.
проблема в том, что в 90% случаев, ты сам и являешься таким вот индусом. Потому что, срок сдачи проекта «вчера». А за другие сроки сдачи тебе не заплатят. КапитализЪм основной двигатель сборки мусора.
Delphi — прекрасно обходится без сборка мусора, потому «Лучший сборщик мусора это тот который не нужен» googol
И Delphi вполне упешно справляется с задачей быстрого создания работающего кода, потому что он оптимизирован под RAD = Rapid Application Development = Быстрое Создание Приложений.
То, насколько успешно справляется с задачами Delphi можно оценить, сравнив количество Delphi-вакансий с количеством вакансий по той же Java.
А вот если код «писан индусами», не понимающими что, как и где вообще происходит (знаменитое «к пуговицам претенции есть?»), вот тогда — с GC всё будет тормозить и жрать память, как не в себя, а без GC — вообще развалится к чертям собачьим.
Есть одна контора, где код, видимо, писан индусами (хотя почему-то основной офис у них в Санкт-Петербурге). Только вопрос: а есть ли в природе хоть одна такая же крутая IDE, написанная крутыми мужиками на C++? Ах да, IDE крутым парням не нужны, vim хватает всем, а IDE — это костыль для индусов, которые не понимают, что они пишут.
Так низкоуровневый системный код и на языках с GC вроде не особо пишется.
Это интересный вопрос, на самом деле. Была, например, jNode. Там управление памятью прописано на Java, и пользователь мог даже свои писать сборщики. Конечно, в регистры процессора всё писалось при помощи ассемблера.
Как-то вот так оно. Не очевидно.
Но на практике самое большое достижение — это уничтожение одной крупной компании (Sun), потеря миллиардов долларов и полнейшее желания у разработчиков отказываться от их любимого BLAS.
Ну вот не хотят — и всё тут. Ни одна система без поддержки нативного кода долго не продержалась: либо он добавлялся (Android, Windows Phone), либо платформа умирала (Blackberry, Java ME). Единственным исключением явился Web, но он потихоньку подходит к тому, что как о платформе для разработки приложений о нём скоро забудут (хотя блоги, конечно, никуда не денутся).
А уж когда в системе оказывается несколько «главных» (какой-нибудь Unity на Android'е) — то тут смело можно забывать и о надёжности и о безглючности (которые, как бы, апологеты GC в первую очередь обещают).
Java вот совершенно не разрабатывалась для вычислительных задач. Но тем не менее, прогресс в скорости исполнения кода в Java-экосистеме впечатляющий.
Но есть языки, которые специально затачивают пот вычисления. Вот, например, сравнение от IBM.
Go, OCaml и Haskell, кстати, генерируют native-код и вполне способны работать с BLAS.
А то, что у нас куча legacy-библиотек, учебников, дао в рабочих коллективах и прочего, что приводит к жизнеспособности языков, подобных Си++. Ну, да. Есть такое. Но это не техническая проблема. Культурная, скорее. Это тоже важно, конечно.
Haskell ghc генерирует нативный код, конечно, но рантайм там жирноват, мягко скажем, не сишечный и даже не плюсовый, поэтому называть это нативным языком несколько странно. А так и JIT в итоге нативный код генерирует, но это же не повод.
Среда для Си, как минимум, включает в себя операционку и некоторое количество защитного и отладочного железа в процессоре. Если мы хотим нечто минимально надёжное, то хотя бы регионы памяти надо поддерживать. А если мы хотим программу хотя бы на 1000 строк кода, то, как минимум, нужен JTAG. То есть, даже в low end микроконтроллерах не всё так просто.
Runtime для Haskell тоже штука такая. Не исследованная. Никто же не пытался его максимально облегчить и оставить минимум необходимого. Насколько мне известно. О! Вспомнил. На самом деле, было такое. Проект House. Они запили полноценную операционку на 1.44 дискету. Микроядро там, конечно, L4 на Си. Но всё же.
Я не говорю, что лучше, а что хуже. Но на картину надо смотреть в целом, с учётом аппаратуры и операционной системы.
На самом деле, с Си ситуация довольно тяжёлая. Например, процессор вынужден постонно обеспечивать видимость строгого порядка доступа к памяти, потому что указатели. И если не обеспечивает, то приходится постоянно вставлять барьеры. А для Haskell такого не надо. И, значит, если у нас Haskell-экосистема, то мы можем позволить себе 16-ти ядерный процессор по цене 4-ёх ядерного, потому что можем транзисторы на ALU потратить, а не на MOB.
И вот, как бы, сиди и думай над tradeoff-ами. Тут можно 10N диссертаций точно влёгкую написать.
Да хороший язык, вполне себе, если писать уметь, конечно, но это для любого языка верно. Я вообще умудряюсь в ряду самых любимых держать плюсы и хаскель.
С другой стороны, вот приду я в условную новую компанию, пусть даже очень большую, а там на какие-нибудь 10к разработчиков хаскель знают хорошо если 50 человек. Тимлиду моему хаскель внедрять будет рискованно, непосредственным коллегам он тоже не сдался, им не пло́тют за изучение, дома семья-дети, какой хаскель ещё, да и вообще на плюсах неплохо кормят. И что делать?
Так я и не утверждаю, что Си++ плохой. Я говорю, что он жизнеспособный, а это даже важнее, чем хороший. Но вопрос в том, чем поддерживается жизнеспособность? Обычно утверждается, что причина в скорости получаемого кода. Я же просто осторожно и, надеюсь, обоснованно сомневаюсь в этом утверждении.
Вот в том же сценарии, когда у нас 10k программистов пишут на Си++, очень даже может быть, что на каком-нибудь Stalin Scheme они бы получали более эффективный код. Scheme — это динамический язык вообще; но картинка такая вот, тем не менее, в которой нужно учитывать, что GCC пишет 100 человек, а Stalin был написан одним профессором.
Почему бы Stalin мог для них быть лучше? Потому что, все же понимают, что 10k программистов пишут, в основном, г-код. А особенность Stalin-а в том, что он процессе компиляции абстрактно исполняет программу, и процентов 50 г-кода посто выкидывает, заменяя константами.
Но Scheme или Haskell вряд ли в такую компанию можно будет внедрить, у ней слишком большая масса, инерция и объёмы legacy-кода. Тем более, что Haskell может и не давать никаких profit-ов именно тем приложениям, которые в этой компании пишут, а осваивать его тяжело. Си++ же не такой уж и плохой язык, и он работает.
Но а зачем в такую компанию внедрять Haskell? Я думаю, такие компании сами отвалятся. Если рядом будет компания, в которой 5k разработчиков, которые на Haskell делают то же самое, но в 2 раза дешевле, в 8 раз безглючнее, и работать оно будет в 64 раза быстрее, потому что на GPU хорошо уложится, то экономика сделает своё дело.
В финансовых секторах Haskell быстрыми темпами распространяется, потому что люди готовы отчаянно бороться против самострела в ноги, и «в 8 раз безглючнее» их мотивирует.
Или вот ещё. Физики всегда любили Fortran. И до сих пор его нежно любят. Но постепенно все переходят на Python. Потому что profit: можно писать программы в 16 раза быстрее, чем на Fortran, а работают они примерно с той же скоростью, или даже в 100 раз быстрее, если попадают на GPU. И, кстати, так получается не только, потому что можно лего использовать библиотеки, которые уже были написаны на Fortran, но и потому что у Python хорошо подходящая для оптимизаций арифметическая семантика, и PyPy способен на чудеса (есть проект Pixie, который отдаёт PyPy абсолютно адский г-код, но JIT его вытягивает на отличную скорость).
Как-то вот так вот оно сейчас неоднозначно. Вот 15 лет назад было хорошо. Хочешь скорости — пиши на Си или Фортран, и не заморачивайся. А сейчас нельзя не заморачиваться. Потому что слева сидит Василий, который ту же программу напишет на Python, в скорости проиграет процентов 15, но на рынок выйдет в 5 раз быстрее. А справа сидит Пётр, который ту же программу будет писать на Haskell, времени затратит, наверное, столько же, сколько и я, но он её ещё проверит при помощи Liquid, и ему не придётся потом полгода исправлять баги в production. И да, коды Васи и Пети тоже будут отлично работать на микроконтроллерах.
И что вот с этим делать?
А про wasm вы не слышали видимо?
Самое главное, что компилировать в него скоро научатся уже все интересные компиляторы (как уже есть скажем компиляция в javascript со Scala, OCaml, Haskell, Rust — и многих других). Проще уже сказать, у кого ее нет.
И в итоге веб, как платформа, скорее всего как раз получит новый виток развития.
А про wasm вы не слышали видимо?Слышал. Более того — слышал от разработчиков этого чуда. Которые так и не смогли ответить на простой вопрос: кто и для чего будет это использовать.
Web-технологии используют потому что просто, быстро и дёшево пишется. Качество результата — так себе, но достоинства превалируют.
Нативный код — дорого и сложно, но результат впечатляет: треубется мало ресурсов и быстро работает.
wasm — дорого, сложно, работает медленнее, чем нативный код и ресурсов жрёт больше. Кому и зачем оно может быть нужно? Если одна «чисто web-ОС» болеше не чисто web, а другая, как и предсказывалось, сдохла?
Во многих применениях самое главное — это быстро довести результат до потребителя. Веб именно это и дает. wasm будет давать еще быстрее, давая возможность скажем перетащить в веб кучу полезного легаси кода.
А ваши «требуется мало ресурсов и быстро работает» — это вообще зачастую ни разу не достоинства, потому что реальные требования такого не содержат. Есть ограничения на ресурсы. Ресурсов типичного ПК хватает, как по памяти, так и по процессору/GPU, при этом достигается приемлемое время отклика, приемлемый FPS и т.п. — значит все хорошо. Вот как-то так часто звучат реальные требования.
И это ваше «качество так себе» — тоже никого не волнует. Я не обобщаю на все случаи жизни, я просто констатирую факты. Вы хотите, чтобы было качественно, медленно делалось и стоило дорого? Бывает и такое.
Но «хочу результат вчера, дешево, и можно тяп-ляп» — тоже еще как бывает.
wasm будет давать еще быстрее, давая возможность скажем перетащить в веб кучу полезного легаси кода.А вот давайте не будем спешить, а? Пока что перенос кода в wasm — это страшная боль. Средств отладки нет, кучи вещей, доступных на всех нативных платформах — нет, когда будет — неизвестно.
А ваши «требуется мало ресурсов и быстро работает» — это вообще зачастую ни разу не достоинства, потому что реальные требования такого не содержат.Реальные требования содержат реальные слабенькие процессоры и реальную батарейку.
Ресурсов типичного ПК хватает, как по памяти, так и по процессору/GPU, при этом достигается приемлемое время отклика, приемлемый FPS и т.п. — значит все хорошо.Вы сюда на машине времени протуннелировали или просто просто 30 лет в пещере проспали?
Откуда у вас взялся legacy-код, который ещё не работает на ПК?
Сегодня legacy-код — это что-то работающее на ПК, но ещё не работающее на телефоне-планшете.
Но «хочу результат вчера, дешево, и можно тяп-ляп» — тоже еще как бывает.Только вот непонятно причём тут wasm вообще. Вот уж там результат «вчера и дёшево» можно не ждать. Так как вы фактически разрабатываете код под новую платформу (со всеми вытекающими «детскими болезнями») — но при этом получаете результат, который работает хуже, чем нативная версия. Кому и зачем она надо?
Для тех, кому нужно «вчера и дёшево» — есть JasvScript, CSS и вот это вот всё. Для тех, кому нужно «качественно и с малым потреблением» — есть нативные SDK. Но кому может быть нужен гибрид, который успешно обьединяет все мыслимые недостатки всех остальных платформ?
Единственный ответ, который существовал до 2016 года «а вот у нас тут в школах миллионы Хромбуков, а скоро ещё FirefoxOS грядёт, ууу… вот тогда...»
Но всё — FirefoxOS больше «не грядёт», а на хромбуках 2017го года работают приложения для Android'а. Ну и? Кому теперь ваш webasm нужен?
В 2009м году — у Native Client'а был шанс. В 2017 у wasm'а — уже нет. Время было безнадёжно растранжирено, окно возможностей закрылось. Забудьте.
А по факту — и для desktop, и для смартфонов давно уже пишут в том числе на JavaScript и даже в embedded-разработку скриптовые языки начали проникать.
даже в embedded-разработку скриптовые языки начали проникать.Какой-нибудь форт там прижился десятилетия назад.
А по факту — и для desktop, и для смартфонов давно уже пишут в том числе на JavaScript«В том числе» — да, но далеко не эксклюзивно. Лет 20 назад большинство так называемых «программистов» писало на Basic'и — и где они сейчас?
нет, рынок нативных приложений не сокращается, нет, разработка на нативных языках и в будущем будут столь же востребованнаЭто вы пытаетесь себя убедить в том, что скоро Visial Basic, ой, извините, Java, нет, я перепутал, конечно же C#, вернее, простите, JavaScript — вытеснят нативные языки.
Претенденты на создание «нового мира» — приходят и уходят, нативные языки остаются. Это как и с поколениями компьютеров: первые четыре — всем известны, пятое — ну вот не случилось.
То же самое и тут: «пена», на которой создают тяп-ляп-приложения меняется, основа — остаётся. Вот только wasm — не попадает ни туда, ни сюда, вот в чём беда.
Это вы пытаетесь себя убедить в том, что скоро Visial Basic, ой, извините, Java, нет, я перепутал, конечно же C#, вернее, простите, JavaScript — вытеснят нативные языки.И где же я такое утверждал?
Я написал, что «доля рынка уменьшается» и это действительно так.
Вот только wasm — не попадает ни туда, ни сюда, вот в чём беда.WASM — ответ на потребность в VM для браузера, в которую удобно кросскомпилировать любой язык по желанию.
То же самое и тут: «пена», на которой создают тяп-ляп-приложения меняется, основа — остаётся.Не удивлюсь, если окажется, что некоторые разработчики на Fortran думали так же.
Не удивлюсь, если окажется, что некоторые разработчики на Fortran думали так же.И были правы, что характерно. Последний стандарт Fortran'а — это Fortran 2008, в следующем году ожидается выход Fortran 2015.
WASM — ответ на потребность в VM для браузера, в которую удобно кросскомпилировать любой язык по желаниюТолько вот что-то не видел я разработчиков, жажадавших получить «VM для браузера». Желающих запустить там legacy-код — видел. Желающих использовать имеющиеся в них DLL-ки — видел тоже. Желающих ломать себе мозги над тем как взять что-то уже работающие и, потратив полгода, получить версию, которая будет работать хуже и требовать ресурсов больше — не видел.
Типичная астронавтика с ответом на вопрос «как нам потратить 5 рублей, чтобы получить результата на 5 копеек». Тех же людей, в сущности, которые выбросили миллионы и сделали бессмысленного, никому не нужного, уродца. Слава богу издохшего не так давно. Почему вы считаете, что WASM будет более востребован — решительно неизвестно.
Тем временем, разработчик самой популярной мобильной платформы во всю продвигает именно веб приложения: https://developers.google.com/web/progressive-web-apps/
Сборка мусора уже решила подавляющее большинство проблем. Сложности с ней возникают только в определённых областях, где особые требования по отзывчивости или расходу памяти, например. Для огромного пласта приложений проблема давно решена и не стоит.
Комментарий похож на нытьё в духе "вам не кажется, что медицина идёт не туда? Столько лет что-то исследуют, мышей травят, новые какие-то лекарства изобретают, говорят, что вот-вот будет хорошо, а люди как болели, так и болеют". На самом-то деле успехи громадны и многие смертельные заболевания успешно научились лечить, но, конечно, это не мешает поныть.
Так что все ровно наоборот — есть 10% или около того задач, для которых паузы на GC это критично, и для них же есть уже давно обходные пути, в виде использования off heap памяти, например. Которые вполне решают проблему, и плата за которые обычно приемлема.
А для 90% приложений платой просто является некоторое повышенное потребление памяти, чтобы GC работал пореже. Это конечно не очень хорошо — но тем не менее, память на сегодня как правило гораздо более дешевый ресурс, чем скажем рабочее время, или время до выхода решения на рынок.
Есть ведь определенная зависимость необходимого размера хипа от размеров данных и порядка аллокации. Если ее не соблюсти — задача оазмещения данных так или иначе превращается в «впихнуть невпихуемое»
Тут важно, не чем конкретно мы ограничены, а что ограничение вообще есть — и оно меньше, чем то, о котором мы всегда мечтаем. Если для решения задачи надо N обьектов — и полюбому надо где-то разместить. И если не хватает памяти — придется их как-то скидывать на диск, уплотнять и тд. Это займет время. Решение — или переписать задачу, чтоб N уменьшилось, или как-то более умно уплотнять объекты, или добавить памяти чтобы все поместилось. Сишники добавляют память или переписывают задачу. Джависты в первую очередь думают, как более умно уплотнять — и при этом над ними ржут сишники. Но при этом джависту доступны все 3 варианта, а сишнику доступно только 2. Если у сишника хип фрагментирован — он никогда не признает, что «а вот java мне б его уплотнила и все работало», он догматично заявит — мало памяти, и никакие аргументы в стиле «ты же сишник, ты можешь все, пойди и отфрагментируй» его не убедят а только разозлят.
Ваш камент сам по себе, в отрыве от контекста, выглядит разумным, и мой выше — точно так же.
Возможно, в рамках концепции я бы что-то возразил, но я уже не помню, в чем там у нас заключалась идея, и какую задачу мы решали — а вспоминать нет смысла.
Возможно, в рамках концепции я бы что-то возразил, но я уже не помню, в чем там у нас заключалась идея, и какую задачу мы решали — а вспоминать нет смысла.Задачу мы решали простую: придумать ситуацию, когда Java'ивсты могут честно сказать: да, все эти «уплотнения и тюнинги» привели к тому, что мы тратим меньше памяти, чем аналогичная программа на C.
Потому что на практике я вижу обычно два случая:
- Программа выделает память массивными, крупными кусками — в этом случае фрагментация нас не волнует, так как работает соображение 0xd34df00d, виртуальная память решает задачу и, в общем, все ухищрения и тюнинг GC никому не нужны: если памяти нет — то её нет.
- Программа работает с множеством мелких обьектов, которые причудливо связаны между собой в хитрые структуры данных. Тут, казалось бы, уплотнение обьектов должно «показать этим C'шникам кто в доме хозяин», но нет же. В случае с C вы можете банально вложить структуры друг в друга, и, тем самым, избежать каких-либо накладных расходов вообще (если структура вложена в другую, то она уж точно от неё не сможет никогда «отфрагментироваться», время на отдельное выделение и освобождение памяти для неё тоже не нужно и память на её «учёт» не требуется совсем), хитрые же подходы Java позволяют к этому, в лучшем случае приблизится
Теоретически можно себе представить ситуацию когда программу на C нельзя преобразовать так, чтобы «выжарить из неё лишний жир» и тогда Java, как бы, должна выиграть — но на практике это происходит весьма редко.
Шучу. Это помню, конечно.
Только вот то, что java тратит больше памяти — вы должны знать. А то, что java уплотняет — я уже рассказал выше. Так что, по всей видимости, вы тоже забыли, в чем стояла задача. Так что, возможно, проблема обсуждалась несколько шире. :)
Вкладывать структуры в си можно, но Все перечисленные вами достоинства этого метода не относятся к фрагментации. Кроме того, вы не упомянули недостатки метода — используя вложенные структуры, нельзя создавать циклические ссылки.
Идея о виртуальной памяти — ну ок. Но насколько понимаю, при наличии дырки размером в страницу в хипе, full gc не вызовется. То есть, большие дырки — это не тот случай, когда проблема фрагментации актуальна.
У меня выходило воспроизводить ситуации, в которых активно вызывается full gc только когда использовал SoftReference. В си аналогии нет — и считайте, что его просто не используют. Если его не использовать в и java, то тормозов gc добиться будет практически нереально.
Кстати, а вы посетитель Benchmarks Game? Просто для статистики хочу знать, сколько человек клюнуло на эту удочку.
Вкладывать структуры в си можно, но Все перечисленные вами достоинства этого метода не относятся к фрагментации.Относятся, ещё как относятся.
Типичный пример:
System.out.format("%f", floatVar)
порождает несколько сотен временных обьектов, часть их которых — долгоживущие (связанные с локалями и т.п.) Вот вам сразу — давление на GC, необходимость компактификации и прочего (так как эти объекты, по хорошему, должны уехать в «долгоживущую» кучу).Сравните с C:
snprintf(buf, ARRAY_SIZE(buf), "%f", f)
— аллоцирует пяток структур, которые все связаны с локалями и, соотственно, «сходу» умирать и создавать фрагментацию не будут (все временные структуры аллоцируются на стеке, для этого alloca есть).То есть проблемы, которые вы пытаетесь решить «тюнингом сборщика мусора» в C отсутствуют изначально — из-за того, что по-другому написана программа.
Кроме того, вы не упомянули недостатки метода — используя вложенные структуры, нельзя создавать циклические ссылки.Так это не недостаток, а достоинство: вам приходится отвечать на вопрос: кто и когда будет создавать этот обьект, а не оставлять это «на волю случая», а потом вылавливать это с помощью инструментария.
То есть, большие дырки — это не тот случай, когда проблема фрагментации актуальна.Тут — согласен. Если вы выделяете память исключительно «крупными кусками», то ни проблемы фрагментации, ни скорость работы аллокаторов и/или GC вас «напрягать» не будут. Да и вопросы о времени жизни отпадают (если вы часто и много выделяете громадные куски памяти, то вашей программе уже ничто не поможет, если редко — за ними можно «уследить»). Можно вообще не использовать «ручных» аллокаторов, а полагаться изключительно на mmap/munmap и поручить всю работу ядру!
Разница между C/C++ и Java — не в том, что ручная аллокация памяти решает ту же самую задачу лучше, чем GC, а в том, что структуры программ оказываются разными!
Если вы перепишите «идеоматический Java-код» на C/C++ — то вы замучаетесь бороться с утечками памяти и ресурсов полученный монстр будет тратить больше, чем в Java!
Кстати, а вы посетитель Benchmarks Game? Просто для статистики хочу знать, сколько человек клюнуло на эту удочку.Нет. На бенчмарках как раз можно заставить всю эту машинерию с многоуровневыми GC в Java работать прилично. В реальном мире — обычно нет, потому что ей начинают заниматься тогда, когда программа уже в таком состоянии, что ей мало что помочь может.
сотен временных обьектов… долгоживущие...
Не знаю, о чем вы. Если это при первом вызове, то возможно что-то такое и есть. А если бы каждый вызов такого pritln добавлял что-то в кучу — вероятно оно бы не работало совсем. Вообще, набор стандартных библиотек действительно хреновастенький, и то что оно не всегда оптимально все делает — исторически сложившийся факт. В настоящее время, желание сломать обратную совместимость и все исправить — все больше. У сишников в этом плане все оказалось настолько сломанным, что чинить уже особо никто не пытается. Хочешь новое — пользуй rust.
Касаемо возражений по существу — на «прогретом» коде, помоему начиная с jvm6, это все будет аллоцироваться в стеке и оптимизироваться (и в седьмой это будет делаться — лучше чем 6), так что масштаб трагедии снова преувеличен.
Что касается локалей — тут все плохо. К нашему вопросу это не относится, но насколько я помню, glib каждый раз когда ты делаешь какой-нибудь %f лазит в файлы локалей. То есть не 1 раз при старте, а вообще каждый раз. (возможно, это уже починили) Так что я бы не сравнивал.
это не недостаток, а достоинство
Это достоинство если под другим углом смотреть. А область применения такого подхода это ограничивает. Так что недостаток. Да, в редких случаях действительно можно получить профит, но на практике обычно профит нужен не в этом месте.
Если вы перепишите «идеоматический Java-код» на C/C++ — то вы замучаетесь бороться с утечками памяти и ресурсов полученный монстр будет тратить больше, чем в Java!
Да, так и есть.
На бенчмарках как раз можно заставить всю эту машинерию с многоуровневыми GC в Java работать прилично
да, но в данном случае там все проще: люди получили 4х кратную просадку в производительности используя разные подходы к распараллеливанию. И утверждают, что это тормоза языка. В результате периодически вижу людей, которые особо не вникая пользуются результатами их сравнения как эталоном — и потом показывают другим. Я рад, что вы туда не ходите. Вы и дальше туда не ходите, там меряют неправильно.
программа уже в таком состоянии, что ей мало что помочь может
С си до такого состояния хрен дорастешь, используя тех же людей который накодили говнокод на жабе :)). Раньше упрешься в какую-нибудь архитектурную сложность, понадобится рефакторинг, ты его не сможешь сделать нормально и тд.
На жабе я уже несколько раз пытался _специально_ создать такую фрагментацию, которая бы долго чистила и уплотняла хип. У меня это выходило более-менее только с мягкими ссылками. Вот если хип загадить SoftReference-ами, то да, может быть full gc, который их грохать будет по одному (если механизм их устаревания не сработает). То есть примерно так: Забиваем весь хип SoftReference-ами, а потом создаем 100 объектов, и можно (теоретически) подобрать так, что что full gc дернется 100 раз, подчищая каждый раз по 1 мягкой ссылке. А вот без мягких ссылок вызвать долгий full gc вообще не получалось. Хотя в интернете есть сведения, что у людей бывало, что хип чистился десятки минут. Вероятно, они нарывались на описанный случай или что-то похожее.
Вообще, тем кому ненравится java и нравится си, надо на rust смотреть. На мой взгляд, си — устаревшая небезопасная штука, и потому должна уйти.
Если это при первом вызове, то возможно что-то такое и есть. А если бы каждый вызов такого pritln добавлял что-то в кучу — вероятно оно бы не работало совсем.При первом вызове — больше 200, при последущих — порядка 100.
И да, оно и не работает. На слабых Android'ах карта начинала дёргаться из-за того, что мы в углу текущие координаты printf'ом выводили из Java. То есть масштабирование картинок, некоторое количество обьектов поверх и прочее — прокатывало, а один-единственный printf — оказывался слишком тяжёл! Ибо приводил к тому, что периодически начинал вызваться GC и всё портить.
На современных телефонах это не очень актуально, наверное, но на HTC Dream… там мы намучались…
У сишников в этом плане все оказалось настолько сломанным, что чинить уже особо никто не пытается.Наоборот — так как раз всё очень эффективно, так что чинить особо и нечего.
Хочешь новое — пользуй rust.Это совсем другое. Это попытка сделать не просто «быстро», а «быстро и безопасно». На то, чтобы работать быстрее C… нет — на это rust не претендует.
Касаемо возражений по существу — на «прогретом» коде, помоему начиная с jvm6, это все будет аллоцироваться в стеке и оптимизироваться (и в седьмой это будет делаться — лучше чем 6), так что масштаб трагедии снова преувеличен.Если бы каждый раз, когда я это слышу я получал по доллару. Я уже про это писал:
Моё первое общение с редактором, написанным на LISP'е примерно так и выглядело: он примерно раз в пару минут останавливался и «уходил куда-то» секунд на пять. Это было ещё на «эталонных» IBM PC XT (вернее клонах), но с тех пор ровным счётом ничего не изменилось, кроме масштаба: всё так же GC приводит к проблемам, только теперь они выражаются в том, что «выпадают кадры» и «дёргаются персонажи» и всё так же можно с этим справиться если выделить системе раз в этак 10 больше ресурсов, чем ей, на самом деле, нужно.Когда в ответ на жалобы про то, что всё тормозит и «дёргается» мне заявляют, что в последней версии этих проблем нету, а после того, как проверка показывает что таки проблемы есть мне говорят, что уж в следующей версии всё точно хорошо будет… и так продолжается не первое десятилетие… увижу программу на Java, которая не требует гигабайтов памяти и 10-ядерного процессора на то, что программа на C спокойно делает на компьютере 10-летней давности — поверю.
К нашему вопросу это не относится, но насколько я помню, glib каждый раз когда ты делаешь какой-нибудь %f лазит в файлы локалей.Да ладно вам. Это оно миллион раз в секунду успевает у меня в файлы локалей слазить? Вы что-то путаете…
Так что недостаток. Да, в редких случаях действительно можно получить профит, но на практике обычно профит нужен не в этом месте.А где он нужен? Мой опыт показывает что оптимизация по размеру используемого кода или по объёму занимаемой памяти «работают» очень часто совсем не так,
С си до такого состояния хрен дорастешь, используя тех же людей который накодили говнокод на жабе :))Совершенно верно. И это — одно из самых больших достоинств C/C++!
Вообще, тем кому ненравится java и нравится си, надо на rust смотреть.Смотрим и думаем пока.
На мой взгляд, си — устаревшая небезопасная штука, и потому должна уйти.Если бы было что-либо со сравнимой эффективностью, но безопасное… rust — хорошая попытка, будем смотреть как развиваться будет.
На слабых Android'а… на LISP
насколько знаю — на андроидах не jvm, а псевдо-jvm. Там что-то с правами гугл и оракл не поделили. Работает она, насколько знаю, хуже, в нее вложено гораздо меньше человеко-часов. Все, что я писал о jvm, относилось к оракловской. Про андроид я не могу сказать ничего.
в ответ на жалобы про то, что всё тормозит и «дёргается» мне заявляют, что в последней версии этих проблем нету,
нет, почему же. В андроидовской это может быть, и, вероятно, есть. И, подозреваю, в последней версии это не починят. И вряд ли в обозримом будущем починят.
Если говорить про IDE, это весьма поверхностное рассуждение. Запустите ту IDE, которой на XT пользовались — тормозить не будет. А то что вы решили пользоваться более новой IDE — так тут никто ничего не обещал :))) На практике в IDE прикручивают фичи до тех пор, пока она не начинает тормозить. Но эти фичи настолько удобны, что все с этими тормозами миряться — и никто не хочет брать старую IDE. Кстати, idea не тормозит особо, и часть ее тормозов связаны с операциями ввода-вывода.
И это — одно из самых больших достоинств C/C++!
Тут вы просто мыслите эмоциями. Для индустрии то, что нужна высокая квалификация программистов — недостаток, и весь мир идет по пути снижения планки.
насколько знаю — на андроидах не jvm, а псевдо-jvm. Там что-то с правами гугл и оракл не поделили.
И, подозреваю, в последней версии это не починят. И вряд ли в обозримом будущем починят.
В последних версиях OpenJDK. Если эта реализация тоже считается плохой, то открытых хороших нет.
весь мир идет по пути снижения планки.
Нужно больше золота… к счастью всё же не весь мир туда еще идёт.
Но эти фичи настолько удобны, что все с этими тормозами миряться — и никто не хочет брать старую IDE.Зато берут emacs и vim.
Конечно только люди, использующие вменяемые языки, где не требуется для простейших действий порождать 100 строк кода. Писать на Java без IDE — это, конечно, ужас… А на C/C++ или каком-нибудь Python'е — нормально, работает…
На то, чтобы работать быстрее C… нет — на это rust не претендует.
Есть принципиальные причины почему раст не может быть, пусть не быстрее, но не медленнее? Ну кроме того, что в оптимизацию ещё надо усилия вкладывать.
Есть принципиальные причины почему раст не может быть, пусть не быстрее, но не медленнее?Многие трюки, которые разрешены с C в rust'е невозможны, так как небезопасны. От того, насколько реально будет потеря в скорости и будет зависеть — будут переходить на rust или нет. Современные компиляторы C по умолчанию используют некоторые замедляющие программы FORTIFYционные приёмы, так что какой-то запас это rust'у даёт. Посмотрим…
Более-менее соглашусь, но всё-таки хочу уточнить, что в расте, в большинстве случаев, есть возможность "обойти безопасность" ради скорости. При этом такие места всё равно будут изолированы.
Но это, в любом случае, вопрос quality of implementation, а не принципиальные причины.Нет, это принципиально. Недаром даже в старом древнем «Турбо Паскакеле» была опция $R. Не выполнять проверку быстрее, чем выполнять, тут природу но обманешь.
Однако дыры, создаваемые этим подходом, так всех задолбали, что современные компиляторы на современных OS всё равно теперь имеют всякие FORTIFYed функции и SENTINELы — а работают они «через раз», так как язык средств для полноценной проверки не даёт. И вот именно сюда, теоретически, может влезть rust.
Посмотрим — удастся ему это сделать или нет.
Конечно. Но мы говорим о компил-тайме, не так ли?Rust (теоретически) выполняет проверки в рантайме. C (теоретически) — не выполняет. Всё.
На практике — да, иногда Rust-компилятор может проверок наизводить, а C-компилятор — навставлять (см. ASAN и прочие развлечения), но стартуют они всё-таки с разных позиций.
Я же про «основную фишку» C: реальные программы норовят-таки завести себе массивчик-другой где-нибудь. Ну там строки, пакеты, вот этот вот всё. И там где C обходится одним-единственным указателем (число, просто адрес в памяти) более безопасным языкам (неважно: это rust, Ada или старый добрый Pascal) приходится таскать более сложные и более «тяжёлые» структуры данных.
Понятно, что если вы хотите хотя бы какого-либо подобия безопасности — иначе нельзя, но вопрос о практическом влиянии этого дела на скорость остаётся открытым…
Неизвестно, сколько будет подключено устройств к машине, куда и что вы будете посылать по сети и т.д. и т.п. — откуда тут взяться «массиву подходящего размера», если вы во время разработки программы не имеете представления ни о том, что будет лежать в этом массиве, ни о размерах оного массива?
Задумывался уже давно, есть ли сборщики работающие на событиях? Чтобы алгоритм был наподобие, — количество ссылок на объект стало равным нулю (количество ссылок считать без построения полного графа, а путем аспектных вставок компилятором, на границы выхода из областей видимости, например), в этом момент для сборщика генерируется событие что объект освободился, и он перераспределяет его память в фоне, работая при этом с равномерной нагрузкой в отдельном потоке. И чем был бы плох такой вариант? Как минимум отпадет проблема пауз.
1) атомарное увеличение-уменьшение количества ссылок не самая быстрая операция, а там нужна именно атомарная, так как часто мы не знаем куда убежала ссылка на объект и какие потоки еще держат данный объект
2) полностью вопроса с паузами он не снимает, хотя и делает на порядки более предсказуемым поведение.
Про второй пункт более подробно:
представьте что у Вас имеется структура в виде дерева и в программе держится только корень,
в какой-то момент корень выходит из зоны видимости и следовательно может быть собран,
после того как собран корень уменьшаются счетчики на объекты которые держались корнем и они тоже отправляются на удаление
и так проходит по всем элементам
в итоге у Вас возникает проблема, что выход из блока и инвалидация всего одной ссылки вызывает каскадную нагрузку на работу с памятью и очень часто предсказать Вы не можете в каком месте это выстрелит.
в классических языках с поколениями пройдет фаза mark и потом copy в новую область все кто выжил, а не будет вызываться пачка мелких удалений, просто пометим всю область как мусор и занулим.
p.s. известный факт: иногда из программы проще выйти по exit сразу в операционную систему, чем аккуратно освободить все участки памяти по очереди =) это касается любого managed языка
— с ручным управлением памятью и детерминированными деструкторами;
— бритвенно острый, как C++;
— но с нормальным поведением по умолчанию, чтобы было меньше способов порезаться;
— с современной системой типов как в Rust.
Чувствую, не дождусь. Придется самому сделать, когда выйду на пенсию.
— с современной системой типов как в Rust.
Почему «как»? Чем Rust не устраивает?
Деструктор детерминирован, способы порезаться сведены к минимуму, но есть unsafe.
http://benchmarksgame.alioth.debian.org/u64q/program.php?test=nbody&lang=ocaml&id=1
http://benchmarksgame.alioth.debian.org/u64q/program.php?test=nbody&lang=rust&id=2
В большинстве случаев в этих тестах benchmarksgame код на Rust и Ocaml работают с примерно одинаковой скоростью. В некоторых случаях Ocaml сильно проигрывает. Но тут не понятно, за счёт чего. Скорее всего, у них оптимизатор для x86_64 не такой хороший, каким он мог бы быть
Я бы сказал что код на Rust процентов на 50 не-идиоматичный. Чего только стоит клон списка тел при подсчёте попарных разниц.
В целом же не вижу особой "перегруженности". Да, OCaml значительно короче — но это объясняется просто другими решениями при дизайне языка. В частности, module-wide type inference. В Rust сознательно ограничили вывод типов телом функции. Ну и по мелочи различия — например в OCaml версии нет вектора как отдельного типа, а в Rust — есть.
Код понятнее от этого, вроде, не становится. А проблема Rust, как мне кажется, ещё и в том, что требуется довольно много boilerplate-кода писать для изменения типов значений.
То есть, вместо того, чтобы думать об алгоритме, который сам по себе сложный, я ещё должен думать о том, как это всё размешается по памяти и явно это прописывать. А алгоритм ещё и работать должен на какой-нибудь комбинации GPU в кластере.
Вот решение той же задачи на SAC: http://www.sac-home.org/doku.php
Вот таким, imho, должен быть идеальный язык программирования. Остальное система должна вывести сама. Сражу скажу, что не считаю SAC идеальным языком. Всё же это функциональный язык для вычислений, ядро операционной системы на нём не написать. Но он быстрый, и куда-то в этом направлении надо идти, мне кажется.
Вас не пугает то количество «магии», которое будет «под капотом» у этого компилятора? Тут я имею в виду даже не столько сложность самого компилятора или его время работы, а то что, если компилятор (или программист) сделает/напишет не так и конечная программа будет работать медленно или не правильно, то какому богу после этого молиться? Ведь надо будет всю эту компиляторную магию выполнить в голове, потому что вменяемую и достаточно быстро работающую IDE-шку для такого сложного языка вряд ли получится сделать.
Тут, наоборот, если компилятор руководствуется формальным выводом типов, а не какими-то неформальными ad-hoc методами, он может дерево выводов в какой-то форме показать и объяснить программисту, почему кусок ассемблера именно такой. В Guile сейчас такое пытаются сделать. Довольно удобно, надо сказать: пишешь функцию, а среда позволяет посмотреть, во что она превращается на разных стадиях оптимизации.
Ну, понимаете, тут же tradeoff простой: либо мы пишем мало кода и редко попадаем в плохие ситуации (ну, потому что, большинство строк кода не такие уж и сложные), либо мы ежедневно пашем как папы Карлы, чтобы получить небольшую delta в функционале.
Release fast, к сожалению, экономически более выгоден. Можно боятся, но машины победили. Это факт. Пора приспосабливаться.
IDE или REPL-ы вполне помогают разобраться с автоматическими типами функций.
Тут дело не в том, что тяжело кнопки давить. А в том, что хочется как можно быстрее переписывать программы. То есть, схема типов важна где-то на уровне интерфейса, а то, как я внутри это всё фигачу должно просто сойтись к этому интерфейсу. Но я хочу свободу в процессе «фигак-фигак и в продакшн» внутри модуля.
Я бы в этом смысле Haskell бы считал идеальным, если бы мог читать его код спокойно.
Хотя вывод типов даже для приватных функций на уровне модуля, по-моему, перебор. Это действительно усложняет и замедляет понимание что происходит внутри функции.
Не знаю. У меня такой опыт: я легко читаю библиотеки на Си (где, в общем-то тоже не шибко круто с типами) или Scheme, но мне очень тяжело читать Haskell или шаблоны в Си++. Типовые переменные увеличивают сложность и объём внимания, который надо уделять коду.
Конкретно этот тест тупой. Тут всё просто — кто смог заюзать векторные инструкции вроде sse3, у того 10 секунд, кто не смог, у того 20 секунд. В языках, которые не сводятся к примитивной математике, больше. Тут никакого мусора нет и он ни на что не влияет. И вообще как-то стыдно уже на benchmarksgame ссылаться-то...
Есть, конечно, ещё коды для курса AIMA, но там Rust-реализаций нет.
На сколько я знаю, у них с ML общий принцип вывода типов. И система типов Rust потомок системы типов ML.
Вывод типов ограничен сознательно, чтобы в элементарном куске кода была аннотация, сводит необходимость зря ломать голову к минимуму.
Работа над теми же non-scoped lifetimes ведётся. Не всё сразу. В конце концов, здесь есть возможность ослабить ограничения. Сильно подозреваю что и вывод типов на уровне модуля со временем завезут.
Но когда читаешь тот же Servo (слегка ковырял ради интереса) если бы у функций не стояли параметры, стало бы оочень тяжело понять что происходит. Ну или вводить какие-то костыли с именованием функций дополнительные. А для маленьких задач — да раздражает слегка. Вероятно, для менее запутанных вещей уровень модуля подходит лучше.
В C# использование var некоторыми гайдами не приветствуется (видел команды, где var не пропускали на review).
В scala, хоть она и позволяет выводить тип для нерекурсивных методов, стандартный de facto статический анализатор заставляет писать типы всех публичных методов явно.
Так что сам по себе вывод типов не всегда и не всеми рассматривается как безусловное благо.
Громоздкости в Rust я не заметил — для своих целей он требует минимум лишних приседаний. Правда изредка встречается некоторая сыроватость, связанная с временем жизни в некоторых случаях, например при обходе мутабельных коллекций. Но это исправляют постепенно.
По мне так к недостаткам Rust можно отнести слабый механизм макросов, основанный на тексте, а не на AST, но это я скалой ударенный.
Из-за первого, например, на Rust нельзя реализовать двусвязный список без использования unsafe или лишнего оверхеда. Ну или бинарное дерево, где узлы хранят сслыки на родителей. Еще в Rust из-за требований к безопасности памяти необходимо проверять гранциы массивов в рантайме при обращении по индексу. В системном языке все это напрягает.
Я готов пожертвовать 100%-й безопасностью памяти в обмен на отсутствие лишней возни и оверхеда. То есть в моем списке требований расту не хватает той самой бритвенной остроты. На том же C++ можно писать безопасный код довольно просто, соблюдая определенную дисциплину. Только хочется иметь «safe defaults». Например, убрать из языка оператор new (за исключением placement new), конструктор копирования по умолчанию и т.п.
Такие список и дерево и так не реализовать без Rc с Weak или ручного управления памятью (unsafe). Вообще не понятны ваши претензии к unsafe: вы пытаетесь сделать что-то, корректность чего, очевидно, нельзя проверить автоматически. Почему вы в этом случае не хотите указать явно, что вы понимаете последствия?
Без проверок границ — get_unchecked.
Я лишь хотел сказать, что для каких-то нетривиальных вещей зачастую приходится прибегать к unsafe. А на системном языке писать нетривиальные вещи как раз приходится часто. Получается, что основное заявленное достоинство языка — безопасность памяти — на практике не особо работает.
— список блоков текста, представленных указателями на внешние буферы;
— деревья типа rope/cord для быстрого поиска по номеру строки;
— индексы для подсветки синтаксиса и т.п.;
— список истории undo, также хранящий указатели на текст во внешних буферах;
— и так далее.
Все это может быть переплетено между собой и хранить ссылки друг на друга.
Я надеюсь, что большинства программистов все же более прагматичный подход. Помимо safe-defaults хорошо бы иметь safe все остальное (на сколько это возможно), а в месте выбранного trade-off'а указать более явно какое решение принято, а в идеале еще и что послужило причиной такого выбора (но кто пишет коменты? правда?).
Вполне возможно, что вы хотите себя чувствовать джедаем и это просто не ваш
Я надеюсь, что большинства программистов все же более прагматичный подход. Помимо safe-defaults хорошо бы иметь safe все остальное (на сколько это возможно)
… меньше задумываться о железе, а больше решать проблемы которые перед ними стоятДля этого есть Java — оличный язык.
Я не хочу чувствовать себя джедаем, просто когда я пишу на системном языке, мне не хочется, чтобы компилятор вставлял мне лишние палки в колеса. Параноидальная проверка лайфтаймов все равно не обеспечит 100%-й безопасности, но значительно усложнит процесс написания и модификации кода. По-моему, мой подход весьма прагматичен. Я просто хочу сделать свою работу, а не ковыряться со всякими
<'a>,
просто чтобы доказать компилятору, что и так вполне очевидно программисту.
Так в этом изначальный посыл и идея языка заключается, что С++ тоже хотели сделать более безопасным и удобным, чем С. Придумали кучу «полезняшек»: 4 типа кастов, шаблоны, множественное наследование и т. п. А в итоге получился огромный монстр для которого во многих проектах от большей части функциона просто отказываются конвенциями.
Вот так и выходит, что просто сделать свою работу на системном языке не получается…
Java тоже не такой уж прям «отличный язык» в своей среде. Иначе бы не появилось куча других языков java-заменителей типа scala, ceylon, kotlin и т. д. Которые тоже статически типизированные, тоже под jvm, но только лучше чем java.
Вы видимо никогда случайно не добавляли элементы в вектор, по которому в это время итерировались. И не забывали инициализировать unique_ptr. И не делали случайное обращение к шареному ресурсу без синхронизации.
Вы видимо никогда случайно не добавляли элементы в вектор, по которому в это время итерировались.Было дело в молодости. Думаю, подобные проблемы можно решать на уровне статического анализатора.
И не забывали инициализировать unique_ptrЭту проблему можно было бы решить, запретив нулевые указатели и убрав из unique_ptr конструктор по умолчанию, требуя тем самым, чтобы unique_ptr всегда содержал действительный указатель. Если нужно представить отстутствие указателя, то на помощь должна прийти система типов: optional<unique_ptr>. Здесь в Rust все сделали правильно.
И не делали случайное обращение к шареному ресурсу без синхронизации.От проблем с шареными ресурсами и сихнронизацией вас ни один компилятор не спасет.
Если есть такое рвение приложить свою руку к созданию такого языка, то подключайтесь к разработке языка D. Там уже много классных плюшек. Например, недавно была статься про диапазоны: https://habrahabr.ru/post/318266/
Синтаксис — С-подобный.
Ну и там еще много всего.
«Об этом мы ещё поговорим ниже»
Так и не поговорили!
Современный подход к сборке мусора