Из чего состоит кэш процессора и где он хранится
Что проверяют
Для Java-разработчика это вопрос не про железо ради железа, а про то, почему один и тот же алгоритм на массиве примитивов работает в разы быстрее, чем на списке объектов. Следом часто спрашивают про false sharing и связь кэша с volatile.
Как отвечать
Кэш это быстрая память SRAM на кристалле процессора, рядом с ядрами. Она хранит копии недавно использованных участков оперативной памяти: обращение в RAM стоит сотни тактов, в L1 единицы.
- L1: свой у каждого ядра, разделён на кэш инструкций и кэш данных, десятки килобайт, задержка несколько тактов;
- L2: обычно на ядро или на кластер ядер, от сотен килобайт до нескольких мегабайт;
- L3: общий для ядер, на десктопе от единиц до десятков мегабайт, у процессоров с 3D V-Cache и серверных чипов больше сотни.
Данные перемещаются не байтами, а строками кэша, обычно по 64 байта. Строка хранит данные, тег адреса и биты состояния. Кэш наборно-ассоциативный: адрес задаёт набор, внутри которого строка занимает одно из нескольких мест. Копии между ядрами согласует протокол когерентности семейства MESI: когда ядро пишет в строку, копии у других ядер становятся недействительными.
Следствия для Java:
- локальность:
int[]лежит в памяти подряд, и процессор заранее подгружает следующие строки.ArrayList<Integer>хранит ссылки на объекты, разбросанные по куче, отсюда промахи; - false sharing: два поля, которые пишут разные потоки, попали в одну строку, и ядра постоянно отнимают её друг у друга. Лечится выравниванием, в JDK для этого есть
@Contended, с ним сделаны ячейкиLongAdder.
Где спотыкаются
Называют устаревшие размеры вроде «L3 до 30 МБ» или помещают кэш на материнскую плату. Там он был в девяностых, сейчас все уровни на кристалле или в корпусе процессора.
Объясняют volatile как «сброс кэша в оперативную память». Кэши когерентны аппаратно, видимость ломают переупорядочивание в компиляторе и JIT, регистры и буферы записи, а volatile запрещает именно это через барьеры памяти.
Не связывают кэш с кодом. Ответ сильнее с примером: обход двумерного массива по строкам и по столбцам даёт кратную разницу во времени.