操作系统 -- Cache和内存
程序局部原理性
CPU大多数时间在执行相同的指令或者与此相邻的指令,这就是程序局部性原理,依据此原理用来缓解CPU和内存之间的性能瓶颈。
内存
内存,从专业角度来讲,内存应该叫做DRAM,即动态随机存储器,内存存储颗粒芯片中的存储单元是由电容和相关元件做成,电容存储电荷的多、少代表数字信号0和1。
重点关注的是:内存的速度还有逻辑上内存和系统的连接方式和结构,如下图所示:

由上图可看出,控制内存刷新和内存读写的是内存控制器,而内存控制器集成在北桥芯片中。随着芯片制造工艺的提升,芯片集成度也越来越高,因此北桥芯片也集成到了CPU芯片中,这大大提升了CPU访问内存的性能。
CPU到内存性能的瓶颈
1、内存条的昂贵程度,超乎想象
2、CPU与内存条读写数据速度的差异:CPU要数据,内存一时给不了怎么办?CPU就得等,通常CPU会让总线插入等待时钟周期,直到内存准备好,就会发现,无论CPU新能多高都没用,内存才是决定系统整体性能的关键。
Cache
开头所讲到的程序的局部性原理:CPU 大多数时间在访问相同或者与此相邻的地址。就想到用一块小而块的存储器,放在CPU和内存之间,就可以利用程序的局部性原理来缓解CPU和内存之间的性能瓶颈。这小而块的存储器就是Cache,即高速缓存。
Catch中存放的是内存中的一部分数据,CPU在访问内存时先去访问Cache,若Cache中有需要的数据就直接从Cache中取出,若没有则需要从内存中读取数据,并同时写入Cache中,但也是由于程序局部性原理,在一段时间,CPU总能从Cache中读到自己想要的数据。
Cache可以集成在CPU内部,也可以做成独立的芯片放在总线上:

Cache主要由高速的静态存储器、地址转换模块和Cache行替换模块组成。
Cache 会把自己的高速静态储存器和内存分成大小相同的行,一行大小通常为 32 字节或者 64 字节。Cache 和内存交换数据的最小单位是一行,为方便管理,在 Cache 内部的高速储存器中,多个行又会形成一组。
Cache 大致的逻辑工作流程如下:
1、CPU 发出的地址由 Cache 的地址转换模块分成 3 段:组号,行号,行内偏移
2、Cache 会根据组号、行号查找高速静态储存器中对应的行。如果找到即命中,用行内偏移读取并返回数据给 CPU,否则就分配一个新行并访问内存,把内存中对应的数据加载到 Cache 行并返回给 CPU。写入操作则比较直接,分为回写和直通写,回写是写入对应的 Cache 行就结束了,直通写则是在写入 Cache 行的同时写入内存。
3、如果没有新行了,就要进入行替换逻辑,即找出一个 Cache 行写回内存,腾出空间,替换行有相关的算法,替换算法是为了让替换的代价最小化。例如,找出一个没有修改的 Cache 行,这样就不用把它其中的数据回写到内存中了,还有找出存在时间最久远的那个 Cache 行,因为它大概率不会再访问了。
Cache带来的问题
虽然Cache带来了性能方面的提升,但同时也给硬件和软件开发开来了问题,那就是数据一致性问题
X86 CPU的Cache结构图:

这是一颗最简单的双核CPU,具有三级Cache,第一级Cache是指令和数据分开的,第二级Cache是独立于CPU核心的,第三级Cache是所有CPU核心共享的
Cache的一致性问题主要包括三个方面:
1、一个 CPU 核心中的指令 Cache 和数据 Cache 的一致性问题。
2、多个 CPU 核心各自的 2 级 Cache 的一致性问题。
3、CPU 的 3 级 Cache 与设备内存,如 DMA、网卡帧储存,显存之间的一致性问题。
为解决上述问题,硬件工程师们开发了多种协议,典型的多核心Cache数据同步协议有MESI和MOESI,这里讲解下MESI协议。
Cache的MESI协议
MESI协议定义了4中基本状态:M、E、S、I,即修改(Modified)、独占(Exclusive)、共享(Shared)和无效(Invalid)
1、M 修改(Modified)
当前 Cache 的内容有效,数据已经被修改而且与内存中的数据不一致,数据只在当前 Cache 里存在。比如说,内存里面 X=5,而 CPU 核心 1 的 Cache 中 X=2,Cache 与内存不一致,CPU 核心 2 中没有 X。

2、E 独占(Exclusive)
当前 Cache 中的内容有效,数据与内存中的数据一致,数据只在当前 Cache 里存在;类似 RAM 里面 X=5,同样 CPU 核心 1 的 Cache 中 X=5(Cache 和内存中的数据一致),CPU 核心 2 中没有 X。

3、S 共享(Shared)
当前 Cache 中的内容有效,Cache 中的数据与内存中的数据一致,数据在多个 CPU 核心中的 Cache 里面存在。例如在 CPU 核心 1、CPU 核心 2 里面 Cache 中的 X=5,而内存中也是 X=5 保持一致。

4、I 无效(Invalid)
当前 Cache 无效。前面三幅图 Cache 中没有数据的那些,都属于这个情况。
Cache 硬件,它会监控所有 CPU 上 Cache 的操作,根据相应的操作使得 Cache 里的数据行在上面这些状态之间切换。Cache 硬件通过这些状态的变化,就能安全地控制各 Cache 间、各 Cache 与内存之间的数据一致性了。
开启Cache
x86 CPU 上默认是关闭 Cache 的,需要在 CPU 初始化时将其开启。
在 x86 CPU 上开启 Cache 非常简单,只需要将 CR0 寄存器中 CD、NW 位同时清 0 即可。CD=1 时表示 Cache 关闭,NW=1 时 CPU 不维护内存数据一致性。所以** CD=0、NW=0 的组合**才是开启 Cache 的正确方法。
开启 Cache 只需要用四行汇编代码,代码如下:
mov eax, cr0
;开启 CACHE
btr eax,29 ;CR0.NW=0
btr eax,30 ;CR0.CD=0
mov cr0, eax
获取内存视图
作为系统软件开发人员,与其了解内存内部构造原理,不如了解系统内存有多大。这个作用更大。
给出一个物理地址并不能准确地定位到内存空间,内存空间只是映射物理地址空间中的一个子集,物理地址空间中可能有空洞,有 ROM,有内存,有显存,有 I/O 寄存器,所以获取内存有多大没用,关键是要获取哪些物理地址空间是可以读写的内存。
物理地址空间是由北桥芯片控制管理的,那我们是不是要找北桥要内存的地址空间呢?当然不是,在 x86 平台上还有更方便简单的办法,那就是 BIOS 提供的实模式下中断服务,就是 int 指令后面跟着一个常数的形式。
由于 PC 机上电后由 BIOS 执行硬件初始化,中断向量表是 BIOS 设置的,所以执行中断自然执行 BIOS 服务。这个中断服务是 int 15h,但是它需要一些参数,就是在执行 int 15h 之前,对特定寄存器设置一些值,代码如下。
_getmemmap:
xor ebx,ebx ;ebx设为0
mov edi,E80MAP_ADR ;edi设为存放输出结果的1MB内的物理内存地址
loop:
mov eax,0e820h ;eax必须为0e820h
mov ecx,20 ;输出结果数据项的大小为20字节:8字节内存基地址,8字节内存长度,4字节内存类型
mov edx,0534d4150h ;edx必须为0534d4150h
int 15h ;执行中断
jc error ;如果flags寄存器的C位置1,则表示出错
add edi,20;更新下一次输出结果的地址
cmp ebx,0 ;如ebx为0,则表示循环迭代结束
jne loop ;还有结果项,继续迭代
ret
error:;出错处理
上面的代码是在迭代中执行中断,每次中断都输出一个 20 字节大小数据项,最后会形成一个该数据项(结构体)的数组,可以用 C 语言结构表示,如下。
#define RAM_USABLE 1 //可用内存
#define RAM_RESERV 2 //保留内存不可使用
#define RAM_ACPIREC 3 //ACPI表相关的
#define RAM_ACPINVS 4 //ACPI NVS空间
#define RAM_AREACON 5 //包含坏内存
typedef struct s_e820{
u64_t saddr; /* 内存开始地址 */
u64_t lsize; /* 内存大小 */
u32_t type; /* 内存类型 */
}e820map_t;
操作系统 -- Cache和内存的更多相关文章
- 操作系统实战45讲笔记- 07 Cache与内存:程序放在哪儿?
程序局部性原理: CPU 大多数时间在执行相同的指令或者与此相邻的指令 时间局部性VS空间局部性: a. 时间局部性:当前访问的指令或数据,也可能在之后访问: b. 空间局部性:当程序访问内存地址x时 ...
- (转)CPU Cache与内存对齐
转自:http://blog.csdn.net/zhang_shuai_2011/article/details/38119657 原文如下: 一. CacheCache一般来说,需要关心以下几个方面 ...
- 轻量级操作系统FreeRTOS的内存管理机制(一)
本文由嵌入式企鹅圈原创团队成员朱衡德(Hunter_Zhu)供稿. 近几年来,FreeRTOS在嵌入式操作系统排行榜中一直位居前列,作为开源的嵌入式操作系统之一,它支持许多不同架构的处理器以及多种编译 ...
- ARM Cortex-A53 Cache与内存的映射关系以及Cache的一致性分析
ARM Cortex-A53 Cache与内存的映射关系以及Cache的一致性分析 题记:如果文章有理解不对的地方,欢迎大家批评指正,谢谢大家. 摘要:本文以Cortex-A53为例,首先分析Cach ...
- Memory Ordering (注意Cache带来的副作用,每个CPU都有自己的Cache,内存读写不再一定需要真的作内存访问)
Memory Ordering Background 很久很久很久以前,CPU忠厚老实,一条一条指令的执行我们给它的程序,规规矩矩的进行计算和内存的存取. 很久很久以前, CPU学会了Out-Of ...
- android中图片的三级缓存cache策略(内存/文件/网络)
实现图片缓存也不难,需要有相应的cache策略.这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且 ...
- python1--计算机原理 操作系统 进制 内存分布
本周内容 '''第一天: 计算机原理 操作系统 第二天: 编程语言 python入门:环境 - 编辑器 变量 基本数据类型 '''``` ## 学习方法 ```python'''鸡汤 - 干货 ...
- 解决linux buffer/cache 消耗内存过高引发的问题
工作中接到DBA报障某台服务器 跑一些大的数据,服务器就无法远程连接,报错,抓过日志叫DELL工程师检测也没问题,系统也重装过, 现在些一些较大的数据就会报如 图错误,由于服务器远在异地城市IDC机房 ...
- cache和内存
CPU与内存 北桥:主桥,主要用来处理高速信号,负责与处理器的联系:CPU通过FSB前端总线来访问内存控制器. 南桥:IO桥,负责IO总线之间的通信,比如PCI总线.SATA.USB等,可以连接光驱. ...
- cache和内存屏障
1 cache简介 1.1 cache缓存映射规则 tag查看cache是否匹配,set index |tag |set index |block offset ||20-bit |7-bit |5b ...
随机推荐
- pnpm 安装和使用
1. 简介 Fast, disk space efficient package manager: Fast. Up to 2x faster than the alternatives (see b ...
- Edge浏览器网站页面如何设置自动刷新
1.浏览器设置 要在Edge浏览器中设置网站页面自动刷新,可以按照以下步骤操作: 打开Edge浏览器,进入你想要自动刷新的网站页面. 在地址栏上方点击"设置和更多选项"(三个水平点 ...
- Flink学习(十六) ProcessFunctionAPI(底层API)
我们之前学习的转换算子是无法访问时间的时间戳信息和水位线信息的.而这些在一些应用场景下,极为重要,例如MapFunction这样的map转换算子就无法访问时间戳或者当前事件的事件时间. 基于此,Dat ...
- 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
大家好!今天给大家带来一个好消息,Dapr(Distributed Application Runtime)1.15版本正式发布啦!对于不熟悉Dapr的朋友来说,Dapr是一个开源的.跨平台的运行时, ...
- 【Python】ini解析ERROR:没有实例属性‘__getintem__’
abaqus python 搭配ini 时,出现AttributeError: ConfigParser instance has no attribute 'getitem' 20230404 ed ...
- SpringBoot的yml文件报org.yaml.snakeyaml.scanner.ScannerException: mapping values are not allowed here in 'reader', line 11, column 16:
报错内容如下: 报错代码如下: 1 spring: 2 cloud: 3 gateway: 4 routes: 5 - id: query_route 6 uri: https://baidu.org ...
- 栈的应用(后进先出 LIFO)--括号匹配问题
博客地址:https://www.cnblogs.com/zylyehuo/ # -*- coding: utf-8 -*- class Stack: def __init__(self): self ...
- Delphi 检测鼠标键盘多久没有活动
function GetInputAwayTime():DWORD; var lpi:TLastInputInfo; begin lpi.cbSize := sizeof(lpi); GetLastI ...
- 【python-日期和时间处理】datetime模块基本使用
1. 获取datetime对象 获取当前datetime对象 方法:datetime.now(cls, tz=None) -> datetime 参数说明: tz:时区信息,不传该参数时,默认使 ...
- Ai满嘴顺口溜,想考研?浪费我几个小时
Trae + claude3.7 事情的经过是这样的: 我有个方法代码如下: /// <summary> /// 获取客户端列表 /// </summary> /// < ...