Принцип работы нового устройства описал Мартин Маас из Калифорнийского Университета в Беркли. В своей работе он предложил вынести в отдельный блок функцию «сборки мусора», при которой процессор удаляет из памяти ненужные данные. На эти операции тратится от 10 до 35% мощности процессора, но отдельный аппаратный блок выполнит эту функцию эффективнее. Такой элемент занимает мало места и не требует большой мощности.
Сборка мусора решает три основные задачи: поддерживает высокую производительность приложений, потребляет минимум ресурсов и обеспечивает минимальные паузы между операциями очистки памяти. Так как встроенные в процессоры сборщики могут выполнить только две из них, то современный подход предполагает поиск баланса между всеми тремя задачами.
Маас и его коллеги предложили добавить к ЦПУ модуль, который выполнит все три задачи гораздо эффективнее. «Пока приложение запущено на процессоре, этот блок параллельно выполняет сборку мусора», — комментирует Маас, — «это значит, что можно создать систему, где ПО в принципе не занимается сборкой мусора и просто использует доступную память». Маас отмечает, что 10% ресурсов, которые процессор тратит на сборку мусора, могут показаться незначительными, но в глобальном масштабе это даёт ощутимую экономию.
Он также указывает, что выделенное устройство работает без пауз. «В повседневной жизни мы не замечаем этих остановок, но в сценариях, где важна скорость, разработчики избегают пауз, тратя ещё больше ресурсов на сборку мусора», — говорит он. Новый блок решает обе эти проблемы, прокладывая путь к более эффективным вычислениям.
Комментарии (43)
strcpy
13.05.2019 20:00+1Вообще такое делали уже: researcher.watson.ibm.com/researcher/files/us-bacon/Bacon12StallFree.pdf
akurilov
13.05.2019 20:21Видимо, не взлетело )
potan
14.05.2019 17:03Не все с первого раза взлетает.
Сейчас железо сильно подешевело и завязанного на GC софта стало заметно больше. Может в этот раз взлететь.Gryphon88
14.05.2019 17:19Насколько я понял статью, предлагается единый хардварный GC «to rule them all»: т.е. и для Java, и .NET, и cpp. Но протестировано только для Java. Мне интересно: единый GC без десятилетий боданий по стандартизации вообще возможен?
yarston
13.05.2019 20:43Лучше б научили компилятор автоматически вызывать free();
vanxant
13.05.2019 23:38Так gc оно и есть — автоматическая вызывалка free().
yarston
13.05.2019 23:56Так оно оверхэд вносит, про который и речь.
Хотя если выделять объекты на стеке, то в С/С++ они удаляются автоматически, без вызова free() / delete() или GC. Но указатель на них нельзя передать за пределы области видимости, в которой они были созданы. Вот если бы компилятор чуть умнее был, и сохранял бы объект при передаче указателя, и сам бы удалял объект, после того, как указатель больше нигде не используется, не нужен был бы GC.vanxant
14.05.2019 03:16Выделять объекты на стеке — это для программ типа диодом на ардуине поморгать.
В реальности у нас давно кругом многопоточность, корутины и асинхронность. Пока вы делаете await, ваши объекты на стеке успеют десять раз протухнуть.
Посмотрите на мучения ядра Linux с асинхронностью. Нет, не неблокирующим i/o, который они торжественно назвали асинхронностью лет 15 назад, а настоящей, которую вот вроде как «скоро» обещают (при том что в винде оно лет 25 как работает). Там делов-то буквально два байта переслать (код ошибки при вызове функций ядра типа read), никаких там указателей. Проблема в том, что в классическом unix эти два байта хранятся не в стеке конечно, но в статической переменной, которая создаётся ядром при создании потока. Только это не работает для асинхронных вызовов, порядок завершения которых не определён.yarston
14.05.2019 09:34-1Вы так пишете, как будто стек совсем не используете. Я его привёл в пример как самый простой вариант автоматического управления памятью, естестественно, он не покрывает всех случаев, иначе и говорить не о чём было бы. Я о том, чтобы компилятор сам выполнял за программистом работу по освобождению памяти, а не только смещал указатель на стек после выхода из локальной области видимости. Пока что такое реализовано только с помощью умных указателей или GC, насколько я знаю, а это оверхед.
0serg
14.05.2019 09:37Смещение указателя на стек и есть освобождение памяти на стеке.
Вы очень плохо разбираетесь в memory management.yarston
14.05.2019 09:51Я знаю, как работает стек. Думал поисследовать тему автоматического управления без оверхэда, запилить для начала статический анализатор, который бы выдавал предупреждения о неосвобождении памяти для ограниченного числа случаев, потом потихоньку допиливать до покрытия 100% возможных случаев. Удивительно, что никому кроме меня тут это не нужно. Ну да ладно.
0serg
14.05.2019 10:37Если говорить о плюсах, то все созданное на стеке всегда автоматически уничтожается компилятором при освобождении стека. В 100% случаев, т.к. как вам уже написали эта память будет повторно использована в следующем же вызове какой-нибудь функции. Выделение и особождение памяти на стеке сводится к перемещению указателя на стек, поэтому работает очень быстро. Оверхед там равен нулю. В силу этой же причины оставить что-то в стеке после выхода из функции невозможно. Если вы хотите переиспользовать созданный на стеке объект после выхода из функции (= очистки стека) то его обязательно надо скопировать в другую область памяти, например в кучу. Любая работа с кучей — это оверхед, но в основном на выделение памяти, а не на ее освобождение. Умные указатели бывают разные — unique_ptr к примеру дает нулевой оверхед на освобождение памяти (относительно ручного особождения). У shared_ptr оверхед равен одной атомик-операции на копирование и освобождение -. В общем тема там большая и интересная, а вы все велосипед изобретаете вместо того чтобы разобраться как работает то что было создано до вас.
Paskin
14.05.2019 07:25+1Указатель на стековые обьекты нельзя передавать за пределы области видимости потому, что при вызовах следующих функций по ходу выполнения программы — их параметры и их локальные переменные располагаются по тем же адресам. А если вы выделяете память в куче а не на стеке — то старый добрый reference counting вполне позволяет передавать такие обьекты куда угодно и при выполнении неких нехитрых правил они будут освобождаться как только будет удалена последняя ссылка.
potan
14.05.2019 17:06Rust умеет. Но это дается не бесплатно, человеку приходится писать так, что бы компилятор мог понять, где это надо делать.
К тому же это мешает использовать TCO.
Gryphon88
13.05.2019 21:29-2Что только люди не придумают, лишь бы VLIW не допиливать, ну или хотя бы не делать независимые ядра под задачу.
AC130
14.05.2019 01:18Если вы знаете способ решить ту же самую задачу лучше, то вы можете написать критическую рецензию на оригинальную статью. Не держите в себе, пусть человек знает что он занимается не тем, тогда он сможет потратить свою жизнь на что-то более полезное.
Gryphon88
14.05.2019 14:28К сожалению, не знаю. Проблемы с управлением памятью есть давно, и примерно столько же их пытаются решить: на уровне языка, на уровне компилятора или его вспомогательных инструментов, на уровне ядра ОС, ну и в железе. Последний способ мне нравится меньше всего: он дорогой, даёт временный буст, который потом приходится тащить в следующие поколения процессоров, а ещё лишняя железка, неподконтрольная программисту, в том числе на уровне ядра, меня банально бесит. Я за решение на программной стороне, пусть даже это и ломает обратную совместимость.
AC130
14.05.2019 19:36В оригинальной статье указаны адреса электронной почты трёх авторов исследования. В параграфах 2-5 введения в общих чертах приводится мотивация авторов, согласно которой они решили делать сборщик мусора в железе. Как вы думаете, могли бы вы развить свои мысли в контексте этой мотивации и сообщить их авторам исследования? Я уверен что вам будут только благодарны за ценный вклад в научный прогресс.
Gryphon88
15.05.2019 14:29Я признаю, что изначально выразился резковато. И статью я читал, мотивация написана про «чем плохи современные GC». Мои мысли перпендикулярны идее статьи: я считаю, что GC вообще не нужен, если стоит вопрос эффективности. Судя по списку литературы, авторы знакомы с этой точкой зрения. Развить эту мысль я не смогу, поскольку не имею достаточных знаний для того, чтобы написать «идеальный» ЯП, а к нему оптимизирующий компилятор и до кучи транслятор с существующих энтерпрайзных ЯП, чтобы идея с восторгом была принята индустрией.
AndrewSu
13.05.2019 22:39-1В повседневной жизни мы не замечаем этих остановок, но в сценариях, где важна скорость, разработчики избегают пауз, тратя ещё больше ресурсов на сборку мусора
Нормальные разработчики в таких случаях выделяют память одним большим куском, а по окончании работы одним куском освобождают. И совсем не тратят времени на сборку мусора.
chaynick
13.05.2019 23:39+2Шел 2019 год, люди изобретали сопроцессор…
Sly_tom_cat
14.05.2019 01:12… очередной сопроцессор…
… в давние времена даже DMA умудрялись процессором/сопроцессорм называть…
old_bear
14.05.2019 10:46Маас и его коллеги предложили добавить к ЦПУ модуль, который выполнит все три задачи гораздо эффективнее. «Пока приложение запущено на процессоре, этот блок параллельно выполняет сборку мусора», — комментирует Маас
Кто нибудь, передайте изобретателю, что процессоры уже довольно давно весьма многоядерные.
roscomtheend
14.05.2019 12:44Учитывая инвалидацию кеша основного процессора, оно точно решит проблему производительности, а не добавит тормозов? Не считая переписывания ядра систем, дабы заюзать это чудо техники (оно ведь не само будет понимать что этот кусок — куча, а там лежат ссылки на объекты, которые надо перетрясти). Да ещё и лочить области памяти, дабы основной процесс, выделяющий что-то, не подрался с этим освободителем, решившим что-то пооптимизировать.
potan
14.05.2019 13:03В Intel iMAX 432 такой был.
Идея хорошая, но там программа не могла сама создавать указатели и сопроцессор сборки мусора мог отличить указатель от данных. К современным процессорам, программируемым на C, аппаратную сбору мусора корректно прикрутить будет очень сложно.
picul
vedenin1980
Раскройте свою мысль, плиз. Что вы тут имеете в виду?
Языки без сборки мусора, вроде C/C++? Там ПО все равно требуется помнить и обрабатывать удаления объектов. В целом, та же сборка только вручную запрограммированная и с человеческими ошибками. Плюс, все равно ОС должна следить кому и какую память она выдавала и вовремя ее очищять.
andreymal
В Rust память автоматически контролируется компилятором без всяких сборок мусора, например. (Но рантаймовые счётчики ссылок тоже есть, разумеется)
vanxant
В расте просто упростили задачу компилятору и рантайму, переложив часть работы на мозг программиста, которому теперь приходится отслеживать всю mutь. Не очень популярный сегодня подход прямо скажем, сегодня модно набрать студентов в стартап и за месяц херак-херак и в продакшен.
nrgian
Нелогично.
Смотрите: допустим, нанимаем не студентов, а квалифицированных и дорогих.
И вместо того, чтобы поручить этим квалифицированным и дорогим специалистам нетривиальную работу, достойную их мозгов — напрягаем мозги этих специалистов mutью. С которой и автоматика справляется.
И именно поэтому и
agalakhov
Как человек, уже несколько лет программирующий на Rust продакшн, скажу: вот очень хорошо, что mut приходится отслеживать. Потому что на этом этапе ловятся логические ошибки. Времена жизни объектов, их мутабельность, оказались очень тесно связаны с правильностью самого алгоритма и зачастую ловят грубые ошибки лучше всяких тестов.
picul
Мне кажется, Вы смешиваете понятия сборки мусора и деструкции объектов. Разумеется, деструкцию все еще нужно выполнять, и в это, кстати, удобнее всего именно в C++ за счет присутствия RAII. А вот сборка мусора (то есть куча бесполезной работы с памятью и счетчиками ссылок только потому, что никто не удосужился сказать, что объекты временные и их можно сложить на стеке) в C++ отсутствует. Про память и ОС вообще не понял.
tmaxx
Мне кажется в статье под «сборкой мусора» имеется в виду «динамическое выделение памяти в куче». То что происходит при malloc() и free(). По умолчанию этим занимается ОС и алгоритмы там далеко не тривиальные. Если в среднестатистической программе таких вызовов много, то отдельный чип сможет немного разгрузить CPU для основного кода.
raid
malloc и free — это функции стандартной библиотеки, а не ОС. От ОС они получают страницы памяти через mmap и освобождают через munmap, если говорить про Linux. Что имеется в виду под сборкой мусора в статье, остаётся только гадать.
picul
В paper'е речь именно о сборке мусора, а не работе с кучей, там об этом прямым текстом написано в самых первых абзацах. А тяжелую нагрузку можно, например, вынести в отдельный поток, чем бы эта нагрузка не являлась.
hssergey
Видимо да, потому что виртуальные машины Java, JavaScript, Python и так далее с точки зрения операционной системы — это пользовательские программы, и каждая виртуальная машина размещает объекты в памяти и реализует логику GC по-своему. И чтобы вынести их сборщики мусора на отдельный процессор, их надо переписывать, реализовывать какой-то общий механизм сборки мусора, единый для разных виртуальных машин, и уже затем его запускать на отдельном процессоре. И то, не знаю как для других языков, но в Java сборка мусора многоуровневая, и есть так называемая полная сборка мусора, где выполнение основной программы приостанавливается, а сборщик подсчитывает все ссылки и вызывает для нужных блоков delete(). Такую сборку мусора стараются делать как можно реже, чтобы не тормозило лишний раз, но все равно как это реализовывать в отдельном чипе, чтобы не приостанавливать выполнение основной программы, непонятно…
tmaxx
Мда, мне стоило открыть оригинал прежде чем писать комментарий…
В статье действительно речь о обычном GC — сборщике мусора в managed-языках (Java, C#, Python). Не очень понятно как планируется сделать аппаратное решение, достаточно гибкое для этого.
rkuvaldin
В свое время были в моде процессоры, которые байткод из коробки поддерживали.