LINUX.ORG.RU

Кэш CPU и сборка мусора


0

3

Интересно, как влияет сборка мусора на эффективность использования кэша процессора?

Я так понимаю, что эффективное использование кэша завязано на то, как часто будут использоваться одни и те же участки памяти. Когда используется сборка мусора то повторное использование одного и того же куска памяти для новых целей возможно только после запуска GC. Последнее стараются отложить на как можно более поздний момент. Поэтому агрессивное выделение/освобождение объектов в определенных ситуациях должно приводить к постоянной перезагрузке кэша. Если реализация алгоритма на с++ допускает активное использование стека и при интенсивном создании/уничтожении объектов в стеке этот стек будет «топтаться на месте», то кэш может вообще не меняться.

С другой стороны данные, с которыми идет активная работа скорее всего были созданы в одно время и лежат в одном месте. Что хорошо, по сравнению с вариантом, когда используется malloc()/free(). В последнем случае сложно предсказать, где будут лежать данные после двух последовательных malloc() (При использовании GC данные почти наверняка будут лежать рядом).

Подводя итоги:

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

2. Если надо много работать с кучей (malloc/free), то GC покажет свои преимущества во всей красе, и по производительности, и по безопасности, и по удобству использования.

В интернете много разговоров про «ништяки» второго случая, и ничего про первый случай. Кто-нибудь может сказать что-нибудь путное по данной теме? Может я чего-то не понимаю и стек в реальных приложениях не дает больших преимуществ?

Подобные рассуждения мне напоминают фразу " ... you say you take care about performance, but you don't take care to measure it".

Последний раз я читал комментарии про CPU cache по делу в обсуждениях разработчиков ядра.

Что хорошо, по сравнению с вариантом, когда используется malloc()/free(). В последнем случае сложно предсказать, где будут лежать данные после двух последовательных malloc() (При использовании GC данные почти наверняка будут лежать рядом).

Я думаю GC использует прямо или косвенно malloc. Если программист не знает, то и GC не знает. Или он использует иные методы выделения памяти.

Поскольку полноценная и безопасная поддержка GC сильно ограничивает возможности использования стека

Ну почему? Значимые типы (к примеру, структуры в C# и D) располагаются на стеке.

то реализации некоторых алгоритмов в языках с нативным GC будут всегда сливать по производительности в сравнении с реализацией на с++

ИМХО, нативное выделение быстрее GCшного, но использование GC устраняет необходимость копирования данных, когда не знаешь, кто и когда их использует (кроме тебя).

sched
()
Ответ на: комментарий от sched

Я думаю GC использует прямо или косвенно malloc

???

pathfinder ★★★★
() автор топика

Suprise, в языках с GC объекты тоже могут создаваться в стэке.

Размещение объекта и степень утилизации кэша между собой вообще не связаны.

mv ★★★★★
()
Ответ на: комментарий от pathfinder

Эээ... любые? В Java/.Net?

Сессно. Если объект маленький и локальный, то его просто нет смысла пропихивать через главный пул памяти. Если объект встроенного типа и совсем маленький (умещается в машинный регистр), то его даже на стэке не будет.

mv ★★★★★
()

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

tailgunner ★★★★★
()
Ответ на: комментарий от mv

Размещение объекта и степень утилизации кэша между собой вообще не связаны.

Может действительно я что-то не так понимаю. Хотел бы по подробнее. Можно ли считать, что в некий момент времени для процессорного кеша не имеет никакого значения в какой части памяти разместится объект? Если этот самый кусок памяти не закеширован, как процессор выкрутится?

pathfinder ★★★★
() автор топика
Ответ на: комментарий от kamre

В Java могут создаваться на стеке.

Фраза из этой ссылки.

Another advantage of stack-based allocation is that it is far more cache-friendly.

pathfinder ★★★★
() автор топика
Ответ на: комментарий от pathfinder

В Java могут создаваться на стеке.

Почитал статью. Если я правильно все понял, в языке нет поддержки выделения объектов в стеке. Но есть некий финт ушами оптимизатора, который, если видит, что объект можно безопасно разместить в стеке, то он его разместит в стеке а не в куче, чтоб сэкономить процессорное время.

Как и с любой другой мудреной оптимизацией, до конца непонятно, когда оптимизация сработает, а когда нет. Вполне возможно, что ручное размещение объектов в стеке можно осуществить в большем числе случаев и более рационально, чем автоматическое. Ведь оптимизатор не знает всей информации по задуманному коду.

pathfinder ★★★★
() автор топика
Ответ на: комментарий от pathfinder

Можно ли считать, что в некий момент времени для процессорного кеша не имеет никакого значения в какой части памяти разместится объект?

Абсолютно. Кэш - это быстрая память, в которой отображён кусок медленной памяти.

Если этот самый кусок памяти не закеширован, как процессор выкрутится?

При обращении к незакэшированной памяти она попадает в кэш.

mv ★★★★★
()
Ответ на: комментарий от pathfinder

Почитал статью. Если я правильно все понял, в языке нет поддержки выделения объектов в стеке.

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

mv ★★★★★
()
Ответ на: комментарий от pathfinder

Вполне возможно, что ручное размещение объектов в стеке можно осуществить в большем числе случаев и более рационально, чем автоматическое.

Это верно для небольших программ, а не для программных систем.

Важно понимать, что Java, как и другие интерпретируемые среды, является сложной программной системой, написанной на языках C++ (JVM) и Java (библиотеки рантайма). А вот программа на C++ всего лишь выражение на языке программирования высокого уровня, понятное человеку и компилятору, допускающее некие ручные оптимизации на низком уровне (например, на уровне языка C и ассемблера, инструкции которых поддерживаются в самом языке и на уровне компилятора).

Объекты C++ и Java ничего общего между собой не имеют, кроме названия. К тому же, простой объект Java имеет оверхед на своё представление в памяти порядка 80 байт.

iZEN ★★★★★
()
Ответ на: комментарий от mv

При обращении к незакэшированной памяти она попадает в кэш.

Ну то есть произойдет очччень медленная операция, которая надолго остановит поток выполнения команд?

pathfinder ★★★★
() автор топика
Ответ на: комментарий от pathfinder

Ну то есть произойдет очччень медленная операция, которая надолго остановит поток выполнения команд?

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

Прямого влияния наличия сборщика мусора на оптимальность заполнения кэша нет.

mv ★★★★★
()
Ответ на: комментарий от mv

Конвейер, который промахнулся, через некоторое время остановится, когда все спекуляции и внеочередные операции выполнятся, но это не остановит другие конвейеры в суперскалярном ядре

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

Правда я не совсем понял, неужели можно так хорошо загрузить конвейеры? Представим, что у нас обычное приложение с одной нитью. Если я правильно понимаю, то при промахе кэша, конвейер может остановится на время, за которое он мог бы выполнить до сотни команд. Соответственно, если мы хотим не заметить этого промаха, другие конвейеры должны иметь возможность выполнить сотню команд, и не должна возникать ситуация, когда все конвейеры выполнят 5-6 команд и станут, ожидая, когда будет закончена загрузка в кэш. Даже не верится, что один поток исполнения можно так хорошо распараллелить по конвейерам.

З.Ы. Я не очень хорошо разбираюсь в тонкостях работы процессора, но мне это очень интересно. Возможно, сказанное мной выше не совсем верно. Буду очень признателен, если кто-нибудь что-нибудь скажет по этому поводу.

pathfinder ★★★★
() автор топика

>В интернете много разговоров про «ништяки» второго случая, и ничего про первый случай

для первого случая и предусмотрен вызов найтивного кода через jni

Karapuz ★★★★★
()

Смешно. Они заботятся о взаимоотношениях кэша процессора и GC, когда размер рантайма и сситемных бибилиотек переваливает сотни мегабайт, а байткод разворачивается в неизвестное количесто нативного кода...

no-dashi ★★★★★
()
Ответ на: комментарий от pathfinder

да прочитай уже дреппера, там всё есть. тебе ссылку дали выше.

mi_estas
()
Ответ на: комментарий от sched

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

у ТС к тому-же небольшое недопонимание про работу памяти. Словосочетания «нативное выделение быстрее GCшного» и кеш процессора несвязанн - ну нет у процессора НАТИВНОГО выделения памяти.. Кеш процессора (точнее микрокод) ещё может разобрать что есть стек, а что не стек, и как-то оптимизировать их в кеше..а вот динамически ли выделена память, через malloc, через GC-ли процессору неведомо.

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

MKuznetsov ★★★★★
()
Ответ на: комментарий от no-dashi

Вообще, да.

Берёте oprofile и смотрите что у вас там с кешем.

Весь этот разговор, кстати, относится только к алгоритмам где много математики и нет вызова сисколлов (обработка изображений например).

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

А для обычных вещей размер кэша процессора можно игнорировать.

P.S. В своё время всё хотел затестить специально скомпиленное ядро линукса указав ему maxmem=16M (или как там...) и ксеон с таким же объемом кеша. если нет I/O должна быть ацкая летучка. Идея вполне реальна особенно со старыми ядрами аля 2.4. ~10 мб памяти хватит на маленький юзерспейс.

mmarkk
()
Ответ на: комментарий от MKuznetsov

Словосочетания «нативное выделение быстрее GCшного»

Я такого не говорил, я говорил про «язык с нативным GC». Эта фраза принадлежит не мне.

pathfinder ★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.