Открыть сервис

LRU

LRU (Least Recently Used, «наименее используемый») — это алгоритм вытеснения кэша, который удаляет элемент, к которому дольше всего не было обращений. Относится к классу политик замещения страниц (page replacement policies) в операционных системах, системах управления базами данных, процессорных кэшах и веб-кэшах. Основная цель LRU — максимизировать вероятность того, что в кэше останутся данные, к которым обратятся в ближайшем будущем, на основе принципа локальности обращений: если к данным давно не обращались, вероятность их повторного использования ниже, чем у недавно запрошенных данных.

История

Идея вытеснения на основе давности последнего обращения восходит к ранним работам по управлению памятью в 1960-х годах. В 1965 году Ласло Белади (László Belády) опубликовал статью «A Study of Replacement Algorithms for a Virtual-Storage Computer», в которой сравнил несколько политик замещения, включая LRU и оптимальный алгоритм (OPT). Белади показал, что LRU близок к оптимальному по числу кэш-промахов при типичных паттернах доступа, хотя и не достигает его. В последующие десятилетия LRU стал стандартом де-факто в операционных системах (например, в ядре Linux для управления страницами памяти) и в аппаратных кэшах процессоров. С развитием веб-технологий LRU начал применяться в прокси-серверах и CDN для кэширования HTTP-ответов.

Принцип работы

LRU основан на поддержании упорядоченного списка всех элементов кэша по времени последнего доступа. При каждом обращении к элементу он перемещается в начало списка (или в позицию «самого свежего»). Когда кэш заполнен и требуется освободить место для нового элемента, удаляется элемент из конца списка — тот, к которому обращались раньше всех.

Формально алгоритм можно описать так:

  1. При запросе элемента X:
  1. При вытеснении: удаляется элемент с минимальным значением времени последнего доступа.

В реализации LRU требуется структура данных, позволяющая быстро (за O(1)) выполнять операции вставки, удаления и перемещения. Обычно используется двусвязный список (Doubly Linked List) в паре с хеш-таблицей: хеш-таблица хранит указатели на узлы списка для доступа за константное время, а список поддерживает порядок по давности.

Реализации

Аппаратная реализация

В процессорных кэшах (например, L1, L2, L3) LRU реализуется на уровне транзисторов с использованием матриц доступа (access matrix) или счётчиков времени. В кэшах с небольшим числом строк (например, 4-канальный ассоциативный кэш) часто применяется псевдо-LRU (pLRU) — приближение LRU, требующее меньше аппаратных ресурсов. pLRU использует битовые деревья (tree-based PLRU), где каждый бит указывает, какая половина набора использовалась недавно.

Программная реализация

В программах LRU реализуется через:

Пример на псевдокоде (Python-подобный): ```python class LRUCache: def __init__(self, capacity): self.capacity = capacity self.cache = {} self.order = DoublyLinkedList()

def get(self, key): if key in self.cache: node = self.cache[key] self.order.move_to_front(node) return node.value return -1

def put(self, key, value): if key in self.cache: node = self.cache[key] node.value = value self.order.move_to_front(node) else: if len(self.cache) >= self.capacity: lru_node = self.order.remove_last() del self.cache[lru_node.key] new_node = self.order.add_to_front(key, value) self.cache[key] = new_node ```

Варианты и модификации

Псевдо-LRU (pLRU)

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

LRU-K

Модификация, учитывающая K последних обращений к элементу. Элемент вытесняется на основе времени его K-го по счёту последнего доступа. LRU-2 (K=2) часто используется в системах управления базами данных (например, в буферном менеджере PostgreSQL) для защиты от «загрязнения» кэша однократными запросами.

ARC (Adaptive Replacement Cache)

Алгоритм, динамически переключающийся между LRU и LFU (Least Frequently Used) в зависимости от паттерна доступа. Разработан в IBM Almaden Research Center (2003). ARC часто превосходит LRU по hit rate на реальных трассах.

Clock (Second Chance)

Приближение LRU, используемое в ядре Linux для управления страницами памяти. Страницы организованы в циклический список с битом доступа. При вытеснении алгоритм просматривает страницы по кругу: если бит доступа установлен, он сбрасывается и страница получает «второй шанс»; если сброшен — страница вытесняется. Это снижает накладные расходы по сравнению с полным LRU.

Применение

Операционные системы

Виртуальная память использует LRU (или его приближения) для вытеснения страниц из физической памяти на диск. В ядре Linux применяется алгоритм Clock (активный с версии 2.6.28), который эмулирует LRU с меньшими накладными расходами. В Windows NT используется модифицированный LRU с разделением на рабочие наборы процессов.

Процессорные кэши

В современных процессорах (Intel Core, AMD Zen) кэши L1, L2 и L3 частично используют pLRU. Например, в Intel Skylake L2-кэш использует 8-канальный ассоциативный кэш с pLRU на основе битовых деревьев.

Базы данных

Буферные менеджеры (например, в PostgreSQL, MySQL InnoDB) применяют LRU с модификациями. InnoDB использует LRU с разделением на «молодую» и «старую» части (LRU with midpoint insertion) для защиты от сканирований, которые могут вытеснить часто используемые страницы.

Веб-кэширование

Прокси-серверы (Squid, Varnish) и CDN (Cloudflare, Akamai) используют LRU для вытеснения устаревших HTTP-ответов. Однако в веб-среде LRU может быть неоптимален из-за неравномерного распределения популярности контента (закон Ципфа), поэтому часто применяются гибридные алгоритмы (например, GDSF — Greedy Dual Size Frequency).

Кэширование данных в приложениях

Библиотеки и фреймворки (например, lru_cache в Python, LRUCache в Java Guava) реализуют LRU для кэширования результатов функций, запросов к API или вычислений.

Преимущества и недостатки

Преимущества

Недостатки

Сравнение с другими алгоритмами

АлгоритмПринцип вытесненияСложностьПрименимость
LRUНаименее используемыйO(1) (с хеш-таблицей)Универсальный, но слаб при сканированиях
LFUНаименее частыйO(log n) (с кучей)Хорош для популярных данных, но дорог
FIFOПервый вошёл — первый вышелO(1)Простой, но низкая эффективность
OPTОптимальный (предсказание будущего)ТеоретическийНе реализуем на практике
ARCАдаптивный (LRU + LFU)O(1)Лучшая производительность на реальных трассах
ClockПриближение LRUO(1) (среднее)Используется в ОС

Интересные факты

Источники

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →