Pull to refresh

Comments 43

это значит, что можно создать систему, где ПО в принципе не занимается сборкой мусора
Скажу по секрету, но никому не рассказывайте: такие системы создают уже давно без всяких дополнительных блоков.
Раскройте свою мысль, плиз. Что вы тут имеете в виду?

Языки без сборки мусора, вроде C/C++? Там ПО все равно требуется помнить и обрабатывать удаления объектов. В целом, та же сборка только вручную запрограммированная и с человеческими ошибками. Плюс, все равно ОС должна следить кому и какую память она выдавала и вовремя ее очищять.

В Rust память автоматически контролируется компилятором без всяких сборок мусора, например. (Но рантаймовые счётчики ссылок тоже есть, разумеется)

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

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


Нелогично.

Смотрите: допустим, нанимаем не студентов, а квалифицированных и дорогих.

И вместо того, чтобы поручить этим квалифицированным и дорогим специалистам нетривиальную работу, достойную их мозгов — напрягаем мозги этих специалистов mutью. С которой и автоматика справляется.

И именно поэтому и
Не очень популярный сегодня подход прямо скажем


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

Мне кажется, Вы смешиваете понятия сборки мусора и деструкции объектов. Разумеется, деструкцию все еще нужно выполнять, и в это, кстати, удобнее всего именно в C++ за счет присутствия RAII. А вот сборка мусора (то есть куча бесполезной работы с памятью и счетчиками ссылок только потому, что никто не удосужился сказать, что объекты временные и их можно сложить на стеке) в C++ отсутствует. Про память и ОС вообще не понял.
Мне кажется в статье под «сборкой мусора» имеется в виду «динамическое выделение памяти в куче». То что происходит при malloc() и free(). По умолчанию этим занимается ОС и алгоритмы там далеко не тривиальные. Если в среднестатистической программе таких вызовов много, то отдельный чип сможет немного разгрузить CPU для основного кода.
malloc и free — это функции стандартной библиотеки, а не ОС. От ОС они получают страницы памяти через mmap и освобождают через munmap, если говорить про Linux. Что имеется в виду под сборкой мусора в статье, остаётся только гадать.
В paper'е речь именно о сборке мусора, а не работе с кучей, там об этом прямым текстом написано в самых первых абзацах. А тяжелую нагрузку можно, например, вынести в отдельный поток, чем бы эта нагрузка не являлась.
Видимо да, потому что виртуальные машины Java, JavaScript, Python и так далее с точки зрения операционной системы — это пользовательские программы, и каждая виртуальная машина размещает объекты в памяти и реализует логику GC по-своему. И чтобы вынести их сборщики мусора на отдельный процессор, их надо переписывать, реализовывать какой-то общий механизм сборки мусора, единый для разных виртуальных машин, и уже затем его запускать на отдельном процессоре. И то, не знаю как для других языков, но в Java сборка мусора многоуровневая, и есть так называемая полная сборка мусора, где выполнение основной программы приостанавливается, а сборщик подсчитывает все ссылки и вызывает для нужных блоков delete(). Такую сборку мусора стараются делать как можно реже, чтобы не тормозило лишний раз, но все равно как это реализовывать в отдельном чипе, чтобы не приостанавливать выполнение основной программы, непонятно…
Мда, мне стоило открыть оригинал прежде чем писать комментарий…

В статье действительно речь о обычном GC — сборщике мусора в managed-языках (Java, C#, Python). Не очень понятно как планируется сделать аппаратное решение, достаточно гибкое для этого.
UFO just landed and posted this here
UFO just landed and posted this here
встроенные в процессоры сборщики
что за звери такие?
Не все с первого раза взлетает.
Сейчас железо сильно подешевело и завязанного на GC софта стало заметно больше. Может в этот раз взлететь.
Насколько я понял статью, предлагается единый хардварный GC «to rule them all»: т.е. и для Java, и .NET, и cpp. Но протестировано только для Java. Мне интересно: единый GC без десятилетий боданий по стандартизации вообще возможен?
Лучше б научили компилятор автоматически вызывать free();
Так gc оно и есть — автоматическая вызывалка free().
Так оно оверхэд вносит, про который и речь.
Хотя если выделять объекты на стеке, то в С/С++ они удаляются автоматически, без вызова free() / delete() или GC. Но указатель на них нельзя передать за пределы области видимости, в которой они были созданы. Вот если бы компилятор чуть умнее был, и сохранял бы объект при передаче указателя, и сам бы удалял объект, после того, как указатель больше нигде не используется, не нужен был бы GC.
Выделять объекты на стеке — это для программ типа диодом на ардуине поморгать.
В реальности у нас давно кругом многопоточность, корутины и асинхронность. Пока вы делаете await, ваши объекты на стеке успеют десять раз протухнуть.
Посмотрите на мучения ядра Linux с асинхронностью. Нет, не неблокирующим i/o, который они торжественно назвали асинхронностью лет 15 назад, а настоящей, которую вот вроде как «скоро» обещают (при том что в винде оно лет 25 как работает). Там делов-то буквально два байта переслать (код ошибки при вызове функций ядра типа read), никаких там указателей. Проблема в том, что в классическом unix эти два байта хранятся не в стеке конечно, но в статической переменной, которая создаётся ядром при создании потока. Только это не работает для асинхронных вызовов, порядок завершения которых не определён.
Вы так пишете, как будто стек совсем не используете. Я его привёл в пример как самый простой вариант автоматического управления памятью, естестественно, он не покрывает всех случаев, иначе и говорить не о чём было бы. Я о том, чтобы компилятор сам выполнял за программистом работу по освобождению памяти, а не только смещал указатель на стек после выхода из локальной области видимости. Пока что такое реализовано только с помощью умных указателей или GC, насколько я знаю, а это оверхед.
Смещение указателя на стек и есть освобождение памяти на стеке.
Вы очень плохо разбираетесь в memory management.
Я знаю, как работает стек. Думал поисследовать тему автоматического управления без оверхэда, запилить для начала статический анализатор, который бы выдавал предупреждения о неосвобождении памяти для ограниченного числа случаев, потом потихоньку допиливать до покрытия 100% возможных случаев. Удивительно, что никому кроме меня тут это не нужно. Ну да ладно.
Если говорить о плюсах, то все созданное на стеке всегда автоматически уничтожается компилятором при освобождении стека. В 100% случаев, т.к. как вам уже написали эта память будет повторно использована в следующем же вызове какой-нибудь функции. Выделение и особождение памяти на стеке сводится к перемещению указателя на стек, поэтому работает очень быстро. Оверхед там равен нулю. В силу этой же причины оставить что-то в стеке после выхода из функции невозможно. Если вы хотите переиспользовать созданный на стеке объект после выхода из функции (= очистки стека) то его обязательно надо скопировать в другую область памяти, например в кучу. Любая работа с кучей — это оверхед, но в основном на выделение памяти, а не на ее освобождение. Умные указатели бывают разные — unique_ptr к примеру дает нулевой оверхед на освобождение памяти (относительно ручного особождения). У shared_ptr оверхед равен одной атомик-операции на копирование и освобождение -. В общем тема там большая и интересная, а вы все велосипед изобретаете вместо того чтобы разобраться как работает то что было создано до вас.
Указатель на стековые обьекты нельзя передавать за пределы области видимости потому, что при вызовах следующих функций по ходу выполнения программы — их параметры и их локальные переменные располагаются по тем же адресам. А если вы выделяете память в куче а не на стеке — то старый добрый reference counting вполне позволяет передавать такие обьекты куда угодно и при выполнении неких нехитрых правил они будут освобождаться как только будет удалена последняя ссылка.
Rust умеет. Но это дается не бесплатно, человеку приходится писать так, что бы компилятор мог понять, где это надо делать.
К тому же это мешает использовать TCO.
Что только люди не придумают, лишь бы VLIW не допиливать, ну или хотя бы не делать независимые ядра под задачу.
Если вы знаете способ решить ту же самую задачу лучше, то вы можете написать критическую рецензию на оригинальную статью. Не держите в себе, пусть человек знает что он занимается не тем, тогда он сможет потратить свою жизнь на что-то более полезное.
К сожалению, не знаю. Проблемы с управлением памятью есть давно, и примерно столько же их пытаются решить: на уровне языка, на уровне компилятора или его вспомогательных инструментов, на уровне ядра ОС, ну и в железе. Последний способ мне нравится меньше всего: он дорогой, даёт временный буст, который потом приходится тащить в следующие поколения процессоров, а ещё лишняя железка, неподконтрольная программисту, в том числе на уровне ядра, меня банально бесит. Я за решение на программной стороне, пусть даже это и ломает обратную совместимость.
В оригинальной статье указаны адреса электронной почты трёх авторов исследования. В параграфах 2-5 введения в общих чертах приводится мотивация авторов, согласно которой они решили делать сборщик мусора в железе. Как вы думаете, могли бы вы развить свои мысли в контексте этой мотивации и сообщить их авторам исследования? Я уверен что вам будут только благодарны за ценный вклад в научный прогресс.
Я признаю, что изначально выразился резковато. И статью я читал, мотивация написана про «чем плохи современные GC». Мои мысли перпендикулярны идее статьи: я считаю, что GC вообще не нужен, если стоит вопрос эффективности. Судя по списку литературы, авторы знакомы с этой точкой зрения. Развить эту мысль я не смогу, поскольку не имею достаточных знаний для того, чтобы написать «идеальный» ЯП, а к нему оптимизирующий компилятор и до кучи транслятор с существующих энтерпрайзных ЯП, чтобы идея с восторгом была принята индустрией.
В повседневной жизни мы не замечаем этих остановок, но в сценариях, где важна скорость, разработчики избегают пауз, тратя ещё больше ресурсов на сборку мусора

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

Шел 2019 год, люди изобретали сопроцессор…
… очередной сопроцессор…

… в давние времена даже DMA умудрялись процессором/сопроцессорм называть…
Требую назвать его «мусорным сопроцессором».
Маас и его коллеги предложили добавить к ЦПУ модуль, который выполнит все три задачи гораздо эффективнее. «Пока приложение запущено на процессоре, этот блок параллельно выполняет сборку мусора», — комментирует Маас

Кто нибудь, передайте изобретателю, что процессоры уже довольно давно весьма многоядерные.

Учитывая инвалидацию кеша основного процессора, оно точно решит проблему производительности, а не добавит тормозов? Не считая переписывания ядра систем, дабы заюзать это чудо техники (оно ведь не само будет понимать что этот кусок — куча, а там лежат ссылки на объекты, которые надо перетрясти). Да ещё и лочить области памяти, дабы основной процесс, выделяющий что-то, не подрался с этим освободителем, решившим что-то пооптимизировать.

В Intel iMAX 432 такой был.
Идея хорошая, но там программа не могла сама создавать указатели и сопроцессор сборки мусора мог отличить указатель от данных. К современным процессорам, программируемым на C, аппаратную сбору мусора корректно прикрутить будет очень сложно.
Sign up to leave a comment.

Other news