当前位置: 首页 > news >正文

[Linux]学习笔记系列 --[mm][list_lru]

文章目录

  • list_lru
      • `list_lru` 概述
      • 原理
      • 使用场景
      • 优点
      • 缺点
      • 其他方案
      • 总结
  • include/linux/list_lru.h
    • list_lru_init
  • mm/list_lru.c
    • list_lru_add 将对象(item)添加到 LRU(最近最少使用)列表中
    • list_lru_add_obj 将对象(item)添加到 LRU(最近最少使用)列表中
    • list_lru_del 从 LRU(最近最少使用)列表中删除指定的对象(item)
    • list_lru_del_obj 从 LRU(最近最少使用)列表中删除指定的对象(item
    • init_one_lru 初始化一个 `list_lru_one` 结构
    • __list_lru_init 初始化一个 `list_lru` 结构

在这里插入图片描述

https://github.com/wdfk-prog/linux-study

list_lru

list_lru 概述

list_lru 是 Linux 内核中的一种通用 LRU(最近最少使用)管理机制,用于高效地管理内存中的对象列表。它通过维护一个链表和相关的计数器,提供了对对象的添加、删除、隔离和遍历等操作。list_lru 的设计目标是优化内存回收过程,尤其是在内存压力下,通过与 shrinker 机制结合,释放不必要的内存资源。


原理

list_lru 的核心原理是通过链表和计数器管理对象的生命周期,并与内存控制组(memcg)和 NUMA 节点结合,提供灵活的 LRU 管理功能。以下是其主要原理:

  1. 链表管理

    • 每个 list_lru 结构维护一个链表(list_head),用于存储 LRU 对象。
    • 对象通过 list_lru_add 添加到链表尾部,通过 list_lru_del 从链表中移除。
  2. 计数器

    • 每个链表都有一个计数器(nr_items),用于记录链表中对象的数量。
    • 计数器的更新通过原子操作实现,确保线程安全。
  3. NUMA 节点支持

    • list_lru 支持 NUMA 节点,每个节点都有独立的链表和计数器。
    • 通过 page_to_nid 获取对象所在的 NUMA 节点,确保 LRU 操作的本地性。
  4. 内存控制组(memcg)支持

    • 如果启用了 CONFIG_MEMCGlist_lru 可以与内存控制组结合,支持基于 memcg 的 LRU 管理。
    • 每个 memcg 都有独立的链表,允许更细粒度的内存回收。
  5. shrinker 结合

    • list_lrushrinker 机制结合,提供对象的回收功能。
    • 当内存压力较大时,shrinker 会调用 list_lru_walk 遍历链表并隔离对象。

使用场景

  1. 内存回收

    • 在内存压力下,通过 list_lrushrinker 机制回收不必要的对象,释放内存资源。
  2. 文件系统缓存管理

    • 文件系统使用 list_lru 管理 inodedentry 的缓存,优化文件系统性能。
  3. NUMA 优化

    • 在 NUMA 系统中,通过 list_lru 的节点支持,确保 LRU 操作的本地性,减少跨节点访问的开销。
  4. 内存控制组(memcg)管理

    • 在启用了 CONFIG_MEMCG 的系统中,list_lru 提供基于 memcg 的 LRU 管理,支持更细粒度的内存回收。

优点

  1. 通用性

    • list_lru 是一种通用的 LRU 管理机制,适用于多种场景(如文件系统、内存回收)。
  2. 高效性

    • 使用链表和原子计数器管理对象,支持高效的添加、删除和遍历操作。
  3. NUMA 和 memcg 支持

    • 支持 NUMA 节点和内存控制组,提供灵活的 LRU 管理功能。
  4. shrinker 结合

    • shrinker 机制结合,优化内存回收过程,减少内存压力。

缺点

  1. 复杂性

    • list_lru 的实现较为复杂,涉及 NUMA 节点、memcgshrinker,可能增加开发和调试的难度。
  2. 性能瓶颈

    • 在高并发场景下,链表操作可能成为性能瓶颈,尤其是链表较长时。
  3. 内存开销

    • 每个 NUMA 节点和 memcg 都需要维护独立的链表和计数器,可能增加内存开销。

其他方案

  1. 直接 LRU 链表

    • 使用简单的 LRU 链表管理对象,不支持 NUMA 和 memcg
    • 优点:实现简单,适用于小规模场景。
    • 缺点:缺乏灵活性,性能较低。
  2. 基于哈希的缓存管理

    • 使用哈希表管理对象,结合 LRU 算法实现缓存管理。
    • 优点:支持快速查找,适用于高性能场景。
    • 缺点:实现复杂,内存开销较大。
  3. 自定义回收机制

    • 根据具体需求实现自定义的回收机制,替代 list_lru
    • 优点:针对性强,适合特定场景。
    • 缺点:增加开发复杂性。

总结

list_lru 是 Linux 内核中的一种通用 LRU 管理机制,提供了高效、灵活的对象管理功能。它通过链表和计数器管理对象,并支持 NUMA 节点和内存控制组,适用于文件系统缓存管理和内存回收等场景。尽管 list_lru 的实现较为复杂,但其通用性和高效性使其成为内核中重要的内存管理工具。在特定场景下,可以考虑使用直接 LRU 链表、哈希缓存或自定义回收机制作为替代方案。

include/linux/list_lru.h

list_lru_init

#define list_lru_init(lru)				\__list_lru_init((lru), false, NULL)
#define list_lru_init_memcg(lru, shrinker)		\__list_lru_init((lru), true, shrinker)

mm/list_lru.c

list_lru_add 将对象(item)添加到 LRU(最近最少使用)列表中

/* 调用方必须确保 memcg 生存期。 */
bool list_lru_add(struct list_lru *lru, struct list_head *item, int nid,struct mem_cgroup *memcg)
{struct list_lru_node *nlru = &lru->node[nid];struct list_lru_one *l;/* 锁定与内存控制组(memcg)关联的 LRU 列表 */l = lock_list_lru_of_memcg(lru, nid, memcg, false, false);/* 如果无法锁定(例如 memcg 生命周期已结束),函数返回 false,表示添加失败 */if (!l)return false;/* 如果对象为空,表示它可以安全地添加到 LRU 列表中 */if (list_empty(item)) {/* 将对象添加到 LRU 列表的尾部 */list_add_tail(item, &l->list);/* 如果添加了第一个元素,则设置 shrinker bit */if (!l->nr_items++)/* Shrinker 位用于标记 LRU 列表需要被回收器(Shrinker)处理 */set_shrinker_bit(memcg, nid, lru_shrinker_id(lru));unlock_list_lru(l, false);atomic_long_inc(&nlru->nr_items);return true;}unlock_list_lru(l, false);return false;
}

list_lru_add_obj 将对象(item)添加到 LRU(最近最少使用)列表中

  • lRU 是一种缓存管理机制,优先保留最近使用的对象并逐步移除较少使用的对象。该函数支持内存控制组(Memory Control Groups,memcg)的感知功能,以优化内存管理
bool list_lru_add_obj(struct list_lru *lru, struct list_head *item)
{bool ret;int nid = page_to_nid(virt_to_page(item));/* return false; */if (list_lru_memcg_aware(lru)) {rcu_read_lock();ret = list_lru_add(lru, item, nid, mem_cgroup_from_slab_obj(item));rcu_read_unlock();} else {ret = list_lru_add(lru, item, nid, NULL);}return ret;
}
EXPORT_SYMBOL_GPL(list_lru_add_obj);

list_lru_del 从 LRU(最近最少使用)列表中删除指定的对象(item)

/* 调用方必须确保 memcg 生存期。 */
bool list_lru_del(struct list_lru *lru, struct list_head *item, int nid,struct mem_cgroup *memcg)
{struct list_lru_node *nlru = &lru->node[nid];struct list_lru_one *l;l = lock_list_lru_of_memcg(lru, nid, memcg, false, false);if (!l)return false;if (!list_empty(item)) {list_del_init(item);l->nr_items--;unlock_list_lru(l, false);atomic_long_dec(&nlru->nr_items);return true;}unlock_list_lru(l, false);return false;
}

list_lru_del_obj 从 LRU(最近最少使用)列表中删除指定的对象(item

bool list_lru_del_obj(struct list_lru *lru, struct list_head *item)
{bool ret;int nid = page_to_nid(virt_to_page(item));if (list_lru_memcg_aware(lru)) {rcu_read_lock();ret = list_lru_del(lru, item, nid, mem_cgroup_from_slab_obj(item));rcu_read_unlock();} else {ret = list_lru_del(lru, item, nid, NULL);}return ret;
}
EXPORT_SYMBOL_GPL(list_lru_del_obj);

init_one_lru 初始化一个 list_lru_one 结构

static void init_one_lru(struct list_lru *lru, struct list_lru_one *l)
{INIT_LIST_HEAD(&l->list);spin_lock_init(&l->lock);l->nr_items = 0;
#ifdef CONFIG_LOCKDEPif (lru->key)lockdep_set_class(&l->lock, lru->key);
#endif
}

__list_lru_init 初始化一个 list_lru 结构

int __list_lru_init(struct list_lru *lru, bool memcg_aware, struct shrinker *shrinker)
{int i;lru->node = kcalloc(nr_node_ids, sizeof(*lru->node), GFP_KERNEL);if (!lru->node)return -ENOMEM;for_each_node(i)init_one_lru(lru, &lru->node[i].lru);// memcg_init_list_lru(lru, memcg_aware);// list_lru_register(lru);return 0;
}
EXPORT_SYMBOL_GPL(__list_lru_init);
http://www.lryc.cn/news/625064.html

相关文章:

  • bun + vite7 的结合,孕育的 Robot Admin 【靓仔出道】(十三)
  • DELL服务器 R系列 IPMI的配置
  • Java基础 8.18
  • 贪吃蛇游戏实现前,相关知识讲解
  • 【LeetCode 热题 100】198. 打家劫舍——(解法二)自底向上
  • MyBatis学习笔记(上)
  • 从双目视差图生成pcl点云
  • linux 内核 - 进程地址空间的数据结构
  • Chromium base 库中的 Observer 模式实现:ObserverList 与 ObserverListThreadSafe 深度解析
  • 套接字超时控制与服务器调度策略
  • 单例模式及优化
  • 高防IP如何实现秒级切换?
  • 【Day 30】Linux-Mysql数据库
  • IDE开发系列(2)扩展的IDE框架设计
  • STC8单片机矩阵按键控制的功能实现
  • 分治-归并-493.翻转对-力扣(LeetCode)
  • Flutter 自定义 Switch 切换组件完全指南
  • Python 面向对象三大特性详解(与 C++ 对比)
  • Android Handler 线程执行机制
  • flutter项目适配鸿蒙
  • 【展厅多媒体】互动地砖屏怎么提升展厅互动感的?
  • 2025年最新美区Apple ID共享账号免费分享(持续更新)
  • 数组学习2
  • Java面试题储备14: 使用aop实现全局日志打印
  • 【HTML】document api
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • C++---有符号和无符号整数的位移操作
  • RabbitMQ:数据隔离
  • kafka 冲突解决 kafka安装
  • Unity进阶--C#补充知识点--【Unity跨平台的原理】Mono与IL2CPP