链表的应用举例:从内存管理到缓存淘汰的艺术

链表的应用举例:从内存管理到缓存淘汰的艺术

链表的应用举例:从内存管理到缓存淘汰的艺术

因为想更好地为义父义母们服务,本文 Bilibili 视频地址

引言:链表之美

在计算机科学的浩瀚星空中,链表犹如一串璀璨的明珠,以其灵活多变的特性闪耀着独特的光芒。它不像数组那样需要连续的存储空间,而是通过指针将离散的内存单元优雅地串联起来,这种"形散而神不散"的特质,使其在众多领域大放异彩。

今天,就让我们一同探索链表在操作系统内存管理和缓存淘汰算法中的精妙应用,感受这种基础数据结构所蕴含的强大力量。

一、链表在操作系统内存管理中的应用

1.1 内存碎片问题:美丽的"伤痕"

想象一下,当我们向操作系统申请一片4GB的连续内存空间时,系统慷慨地满足了我们的请求。随后,我们通过malloc申请了1GB的内存,这时原有的内存版图便悄然发生了变化:

void* memory =malloc(4*1024*1024*1024);// 申请4GBvoid* chunk1 =malloc(1*1024*1024*1024);// 申请1GB

此时,原本完整的4GB内存被分割成了三部分:

  • 已分配的1GB内存块
  • 剩余的3GB空闲内存中,由于内存对齐等因素,可能会形成两个碎片:2GB和1GB

这种"碎片化"现象就像一面完整的镜子被打碎后形成的碎片,虽然每个碎片依然可用,但已不再连续。

1.2 链表:内存碎片的"穿线者"

操作系统如何管理这些分散的内存碎片呢?答案就是链表!系统会将不同的内存碎片通过指针串联起来,形成一个空闲内存链表:

next

next

2GB内存块

1GB内存块

NULL

图1:空闲内存链表示意图。每个内存块通过next指针连接,最后一个块指向NULL

这种链表结构的美妙之处在于:

  1. 动态管理:可以随时插入或删除节点,适应内存的分配与释放
  2. 空间高效:仅需少量指针空间即可维护整个内存区域
  3. 灵活性:不同大小的内存块可以共存于同一链表中

当程序再次申请内存时,系统会遍历这个链表,寻找合适大小的内存块(首次适应、最佳适应等策略),犹如一位精明的裁缝在布料堆中寻找合适的布料。

二、缓存:速度与容量的优雅平衡

2.1 缓存的概念:计算机世界的"速记本"

缓存,这个听起来有些神秘的概念,实际上是高速设备对低速设备的一种优雅妥协。它是计算机系统中不可或缺的"中间人",在速度与容量之间寻找最佳平衡点。

定义:

缓存是位于高速设备与低速设备之间的一种临时存储区域,用于减少访问低速设备的次数,提高系统整体性能。

2.2 缓存的工作原理:多级存储的和谐共舞

让我们以硬盘和内存为例,构建一个缓存工作的场景:

快速访问

快速访问

较慢访问

更慢访问

慢速访问

CPU

L1 Cache

L2 Cache

主内存

硬盘

图2:计算机存储层次结构。从上到下速度递减,容量递增

假设硬盘中有512GB数据,而内存中仅有1GB的缓存空间。当CPU需要数据时:

  1. 首先查询内存缓存(命中则直接使用)
  2. 若未命中,则从硬盘读取数据,并按照一定策略存入缓存

这种多级缓存的设计,就像图书馆的借阅系统:最常用的书籍放在触手可及的书架上(L1缓存),次常用的放在稍远的书库(内存),而所有藏书则存放在总仓库(硬盘)。

2.3 缓存内部的数据结构:从链表到哈希链表

缓存内部如何组织数据?最简单的实现方式是使用链表:

typedefstructCacheNode{void* data;size_t size;structCacheNode* next;} CacheNode;

但随着数据量增大,链表的O(n)查找效率成为瓶颈。于是,聪明的工程师们将其升级为哈希链表——结合哈希表快速查找和链表有序特性的混合结构:

双向链表

哈希表

指针

指针

prev

next

prev

next

Key1

节点A

Key2

节点B

...

...

图3:哈希链表结构示意图。哈希表提供快速访问,双向链表维护访问顺序

这种结构完美平衡了查找效率和顺序维护的需求,为缓存淘汰算法奠定了基础。

三、LRU缓存淘汰算法:时间价值的体现

3.1 LRU算法原理:最近最少使用的智慧

LRU(Least Recently Used)算法是缓存淘汰策略中的经典之作,其核心思想是:

当缓存空间不足时,优先淘汰最久未被访问的数据

这就像我们整理书架:经常阅读的书籍放在显眼位置,而长时间不碰的书籍则被收入箱底。

3.2 LRU实现示例:四步看懂淘汰过程

假设我们的缓存只能容纳4个数据项,初始状态为空的链表:

头节点

尾节点

表1:LRU缓存操作示例

操作步骤访问数据缓存状态(最新→最旧)动作说明
1A[A]插入A
2B[B, A]插入B
3C[C, B, A]插入C
4D[D, C, B, A]插入D
5A[A, D, C, B]A被访问,移动到头部
6E[E, A, D, C]缓存已满,淘汰最旧的B

当缓存命中时(如步骤5访问A),将该节点移至链表头部;当缓存未命中时(如步骤6访问E),将新数据插入头部并淘汰尾部节点。

3.3 代码实现关键点

以下是LRU缓存的核心操作伪代码:

classLRUCache:def__init__(self, capacity): self.capacity = capacity # 缓存容量 self.cache ={}# 哈希表,存储键值对 self.head, self.tail = Node(), Node()# 双向链表头尾哨兵节点 self.head.next, self.tail.prev = self.tail, self.head defget(self, key):if key in self.cache: node = self.cache[key] self._move_to_head(node)# 移至头部表示最近使用return node.value returnNonedefput(self, key, value):if key in self.cache: node = self.cache[key] node.value = value self._move_to_head(node)else:iflen(self.cache)>= self.capacity: removed = self._remove_tail()# 淘汰最久未使用的del self.cache[removed.key] new_node = Node(key, value) self.cache[key]= new_node self._add_to_head(new_node)

这段代码展现了LRU算法的精髓:

  1. 双向链表:维护访问顺序,头部是最新访问,尾部是最久未访问
  2. 哈希表:提供O(1)的快速查找能力
  3. 淘汰策略:当空间不足时,自动移除链表尾部的节点

四、链表应用的深度思考

4.1 性能对比:不同场景下的选择

表2:不同数据结构在缓存中的性能对比

数据结构插入效率查找效率删除效率顺序维护内存开销
数组O(n)O(1)O(n)优秀
单向链表O(1)O(n)O(n)良好中等
哈希链表O(1)O(1)O(1)优秀较高

从表中可见,哈希链表在缓存场景中几乎提供了全面的性能优势,这也是现代缓存系统广泛采用它的原因。

4.2 现实世界的变种算法

在实际系统中,纯粹的LRU可能并非最优选择,因此衍生出了多种变体:

  • LRU-K:考虑最近K次访问的历史
  • 2Q:两个队列分别维护热数据和冷数据
  • ARC:自适应调整缓存策略

这些算法都在不同程度上优化了基础LRU的表现,体现了计算机科学家们对完美的不懈追求。

结语:链表的永恒魅力

从内存管理的碎片整理,到缓存淘汰的策略实现,链表这一看似简单的数据结构展现了惊人的适应力和表现力。它就像计算机世界中的万能胶水,将离散的元素有机连接,构建出高效的系统。

正如Donald Knuth所言:"链表是递归的数据结构,而递归是计算机科学的核心概念之一。"理解链表的应用,不仅能够帮助我们解决实际问题,更能培养计算思维,感受计算机科学的内在美感。

链表的应用举例:从内存管理到缓存淘汰的艺术

在技术日新月异的今天,链表这一古老的数据结构依然焕发着勃勃生机,这或许就是经典永恒的魅力所在。

Read more

昇腾 (Ascend) NPU 实战指南:在 GitCode Notebook 中玩转 CodeLlama

昇腾 (Ascend) NPU 实战指南:在 GitCode Notebook 中玩转 CodeLlama

1.前言 随着大模型技术在软件开发领域的深入应用,越来越多的开发者开始尝试在本地或云端环境部署代码生成模型。华为昇腾(Ascend)计算产业随着 CANN 软件栈的不断成熟,已成为运行各类开源 LLM 的重要算力底座。 本文将以 CodeLlama 这一广受欢迎的代码生成模型为核心,结合 GitCode Notebook 提供的在线开发环境,讲解如何在本地或服务器的昇腾 NPU 环境中完成从依赖配置、模型加载到代码生成的完整流程。文章将通过结构化的流程讲解与可操作的示例代码,引导你在昇腾生态中顺利完成 CodeLlama 的部署与运行。 接下来我们就开始进行动手实践吧。 GitCode官网:https://gitcode.com/。 2.GitCode Notebook 环境准备 GitCode 是面向中国开发者的一站式代码协作与模型应用平台,集成了开源仓库托管、在线运行环境、模型中心等能力。其中的 GitCode Notebook 提供了无需本地配置的云端交互式开发环境,支持直接在浏览器中编写、运行和调试代码,非常适合进行大模型试验与算子验证。 进入Gitcode官网

By Ne0inhk

Modelsim仿真软件的,安装/破解/使用教程大全

仿真前言         作为一名FPGA工程师,在做FPGA开发时,使用仿真一定是最重要的,有些人喜欢写完代码直接上板子调试,根本不会做一点点仿真;如果是简单的逻辑代码,有十足的把握,那就不用仿真,可以直接上板子调试,但是,如果您是在做工程的开发,很多代码都是第一次编写调试,那么,代码的仿真是一定要做的,你要问我为啥,我个人觉得,每次把自己写完的代码,放到modelsim上面仿真看一下波形,就像考试的时候,拿着参考答案在做题一样的感觉,各个波形的变化你都会看的一清二楚,但是如果你用在线逻辑分析仪看RTL的仿真,那真的是太耗费时间;         我知道这个时候就会有人说了,Modelsima仿真有啥用呀,和下板子调试完全是两个概念,包括信号延迟,信号质量,眼图等都不一样,说的也对,但是实际情况是,这些人眼高手低,觉得仿真这种操作太麻烦;仿真虽然不能完全模拟真实的硬件信号,硬件延迟也没法准确仿真,但是他能让你在开发的时候,规避掉95%的因为代码引起的错误,这会让你在调试阶段节省很多时间;然后剩下的调试你必须 要在硬件调试时才会发现并且解决;        在调试阶段,FPGA为

By Ne0inhk

75元!复刻Moji 2.0 小智 AI 桌面机器人,基于乐鑫ESP32开发板,内置DeepSeek、Qwen大模型

文末联系小编,获取项目源码 Moji 2.0 是一个栖息在你桌面上的“有灵魂的伴侣”,采用乐鑫 ESP32-C5开发板,配置 1.5寸 360x360 高清屏,FPC 插接方式,支持 5G Wi-Fi 6 极速连接,内置小智 AI 2.0 系统,主要充当智能电子宠物的角色,在你工作学习枯燥时,通过圆形屏幕上的动态表情包卖萌解压,提供情绪陪伴;同时它也是功能强大的AI 语音助手,支持像真人一样流畅的连续对话,随时为你查询天气、解答疑惑或闲聊解闷,非常适合作为极客桌搭或嵌入式学习的开源平台。 🛠️ 装配进化 告别手焊屏幕的噩梦。全新设计的 FPC 插座连接,排线一插即锁,将复刻门槛降至最低。 🚀 性能进化 主控升级为 ESP32-C5。支持 5GHz Wi-Fi 6,

By Ne0inhk

阿里云的moltbot机器人使用钉钉的Stream流式接入

注意 1. 这个不需要工作流 2. 这个不需要开放外网 具体方法: 1.check代码https://github.com/DingTalk-Real-AI/dingtalk-moltbot-connector 2.package.json增加如下代码 "moltbot": { "extensions": ["./plugin.ts"], "channels": ["dingtalk-connector"], "installDependencies": true } 3.安装插件 moltbot plugins install dingtalk-moltbot-connector 4.增加钉钉配置~/.moltbot/moltbot.json;如果有了进行提花 { "channels"

By Ne0inhk