Ответ
Cache line (кэш-линия) — это минимальная единица данных, которой оперирует кэш процессора. При чтении из памяти в кэш загружается не один байт, а целая линия фиксированного размера.
Основные характеристики:
- Размер — обычно 64 байта на современных x86/x64 процессорах
- Выравнивание — адрес начала линии кратен её размеру
- Атомарность — операции с линией атомарны на уровне кэша
Как это работает:
// Пример проблемы false sharing (ложного разделения)
struct Data {
int a; // Поток 1 постоянно пишет сюда
int b; // Поток 2 постоянно пишет сюда
};
// Если a и b попадают в одну кэш-линию (64 байта),
// то при изменении a в потоке 1, вся линия помечается невалидной
// в кэшах других ядер, вызывая постоянную синхронизацию кэшей.
Пример на Java с @Contended (Java 8+):
import sun.misc.Contended;
public class FalseSharingExample {
// Аннотация гарантирует, что поля будут в разных кэш-линиях
@Contended
public volatile long value1 = 0L;
@Contended
public volatile long value2 = 0L;
// Без @Contended оба long (по 8 байт) поместятся в одну линию (64 байта)
// С @Contended JVM добавит padding между полями
}
Практическое значение:
- Ложное разделение (False Sharing) — основная причина проблем с производительностью в многопоточных приложениях
- Выравнивание структур — оптимизация доступа к памяти
- Размер структур данных — проектирование с учётом размера кэш-линии
Оптимизация доступа:
// Плохо: массив структур (AoS)
class Point { float x, y, z; }
Point[] points = new Point[1000];
// При обработке только координаты x, в кэш загружаются ненужные y и z
// Лучше: структура массивов (SoA) для векторной обработки
class Points {
float[] x = new float[1000];
float[] y = new float[1000];
float[] z = new float[1000];
}
// При обработке x[] кэш-линии содержат только нужные данные
Размеры на разных архитектурах:
- x86/x64: 64 байта
- ARM: обычно 32 или 64 байта
- IBM POWER: 128 байт