学软件的人为什么也要啃《计算机组成原理》里的主存储器?这事儿我得好好聊聊。我见过不少写了好几年业务代码的同事,一聊到内存、缓存、寻址、字节对齐就发怵,遇到线上性能问题只会加索引、上缓存、扩机器,治标不治本。而这些年我自己的体会是,凡是能把主存储器这块吃透的人,写出来的代码稳定性、性能、甚至排错能力都明显高一个档次。这门课不是硬件工程师的专利,它是所有想在技术路上走深的软件工程师的地基。
这篇文章就聚焦《计算机组成原理》里"主存储器"这一大块,把存储层次为什么这么设计、SRAM和DRAM到底差在哪、芯片怎么扩展成内存、校验码怎么干活、以及现代内存的时序参数是怎么一回事,一件件拆开讲清楚。顺带把我自己学习和实操中踩过的坑、总结的规律一并放出来,希望能帮你省下走弯路的时间。
1. 存储层次:为什么CPU和内存之间要"层层设防"
1.1 从寄存器到硬盘:速度、容量、价格的三角博弈
计算机组成原理一上来就会告诉你,整个存储系统是个金字塔结构:
| 层级 | 典型硬件 | 速度量级 | 容量量级 | 单位成本 |
|---|---|---|---|---|
| 寄存器 | CPU内部触发器 | 0.3ns | 几十到几百B | 极高 |
| Cache(缓存) | SRAM | 1~10ns | 几十KB~几十MB | 高 |
| 主存(内存) | DRAM | 50~100ns | 几GB~几十GB | 中 |
| 辅助存储器(磁盘/SSD) | 磁/闪存 | 毫秒~微秒级 | 几百GB~几TB | 低 |
这个金字塔不是拍脑袋设计的,而是三条底层规律的必然结果:
-
越快越贵。SRAM一个存储单位要6个晶体管,DRAM一个存储单位只要1个晶体管加1个电容,所以同样容量的SRAM比DRAM贵几十倍,根本不可能拿来做大容量内存。
-
CPU太快了。3GHz的CPU一个时钟周期大约0.33ns,而DRAM的访问延迟大约在几十到上百纳秒。如果CPU每次都直接访问主存,大部分时间都在空转等待数据,性能直接被内存拖垮。
-
局部性原理是这一切能成立的基石。程序在时间和空间上访问的数据都呈现出聚集效应:刚访问过的数据短时间内大概率还会再访问(时间局部性),某个地址附近的数据大概率会接着被访问(空间局部性)。因为有了局部性,我们才能把最常用的数据放在最快的层,把不常用的数据放到慢速大容量层。
所以存储层次的核心思路就一句话:用价格换速度,用容量补延迟,用局部性做赌注。
1.2 主存的位置:承上启下,卡在所有数据的咽喉上
主存储器在金字塔里的位置非常关键。往上,它要给Cache提供数据;往下,它要从磁盘/SSD加载程序和数据。它就像一家公司的中层经理,上面是要求极高的老板(CPU),下面是大仓库(磁盘)。所有指令、数据在被CPU使用之前,都必须经过主存这一道关卡。
理解这一点,你就会明白为什么主存的性能参数、容量、校验机制、扩展方式,会直接影响整台机器的表现。操作系统里的虚拟内存、分页机制、内存映射文件,底层全靠主存这套物理机制撑住。数据库的Buffer Pool、Redis的持久化策略、消息队列的内存缓冲,其实都是在用软件手段绕过"主存不够快、不够大"的物理约束。
1.3 主存储器里装着什么:RAM、ROM、Cache、虚拟内存一次理清
初学者特别容易把一堆名词搞混,我在这里给你画一条清晰的边界:
- RAM(随机存取存储器):可读可写,断电数据丢失。就是日常说的内存条。
- ROM(只读存储器):出厂写入数据,断电不丢。一般用来存固件、启动程序(BIOS/UEFI)。《计算机组成原理》考试里常考ROM和RAM的区分就到此为止。
- Cache(高速缓存):本质是SRAM,分为L1/L2/L3,放在CPU内部或紧挨着CPU,用来缓存主存中的数据副本。
- 虚拟内存:操作系统借助主存和磁盘构建的一种逻辑存储空间抽象,不是一块独立硬件。它让程序以为有一个极大的连续地址空间,实际上数据在物理内存和磁盘之间来回调度。
主存储器在教学和考试语境下,最核心的就是DRAM构成的主存阵列——它由存储芯片、地址译码器、数据总线、控制逻辑组成。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 存储单元背后的物理逻辑:SRAM和DRAM的存储原理
2.1 SRAM:六管锁存,快而贵
SRAM(静态随机存取存储器)的存储位电路叫六管存储单元——4个晶体管构成两个交叉耦合的反相器,再加2个晶体管做读写控制门。
它的核心机制是锁存(Latch)。两个反相器首尾相连,形成一个双稳态电路:A点高电平、B点低电平是一种稳定状态;A点低电平、B点高电平又是另一种稳定状态。只要不断电,这个状态就能一直保持下去,不需要刷新。这就是"静态"二字的意思。
因为不需要周期性刷新,结构逻辑简单,所以SRAM的访问速度非常快,能跟上CPU的高速访问节奏。但代价是面积大、集成度低、价格高——一个存储位就要6个晶体管,而DRAM一个存储位只要1个晶体管加1个电容。所以SRAM只适合用在CPU缓存、寄存器这种容量小但对速度极度敏感的场景。
2.2 DRAM:单管电容,密度高却要不停"续命"
DRAM(动态随机存取存储器)的存储单元由一个晶体管和一个电容组成。电容充电代表1,放电代表0。这就是"动态"的由来——电容会漏电,电荷保持不住,所以必须不停地充电刷新,否则信息就丢了。
DRAM的密度高、成本低,但也带来三个很阴间的工程问题:
- 读破坏性:读操作本质上是从电容里取电荷,一读就把电容里的电荷放掉了,所以读完必须立刻回写(这叫作"读后再生")。
- 刷新:即使不读,电容也在持续漏电,必须每隔一段时间把整行的数据读出来再写回去。这个周期通常是64ms。
- 行激活开销:DRAM的物理结构是行列矩阵,访问一个数据先要激活行(行缓冲),再选择列,这个过程比SRAM慢得多,而且带有固定功耗。
2.3 刷新周期计算:一道必考的算术题
刷新是DRAM特有的"续命机制",理解它,你才能真正懂得DRAM的时序为什么这么别扭。
DRAM按行刷新,刷新周期通常是64ms。以4096行的DRAM芯片为例:
code复制刷新一行需要的时间:假设单个刷新命令耗时 tRC = 50ns
总行数:4096 行
每行刷新间隔 = 64ms / 4096行 = 15.625μs
刷新总开销占比 ≈ (4096 × 50ns) / 64ms ≈ 0.32%
这个计算说明什么?刷新开销本身不算大,但它搅乱了访问流水线。 因为刷新时内存在忙,CPU来了读请求只能等待,这在实时性要求高的场景里会造成刺不准的延迟毛刺。这也是为什么有些高性能系统会刻意避开内存刷新风暴(同源行集中刷新)的时间窗口。
2.4 存储器芯片的宏观结构:矩阵、译码器、IO控制
单看存储单元还不够,你得把整个芯片的结构画出来才能理解外部引脚的逻辑。
典型DRAM芯片的内部结构包括:
- 存储矩阵:几千行乘几千列的阵列,行列交叉点是存储单元。
- 行地址译码器和列地址译码器:行地址和列地址分时复用同一组地址引脚(比如地址线A0~A13,先发行地址,再发列地址),靠RAS(行地址选通)和CAS(列地址选通)两个控制信号区分。复用引脚能大幅减少芯片引脚数量,但代价就是访问时序变复杂。
- 行缓冲(Row Buffer):激活一行时,这一整行的数据会被读到行缓冲里,之后对同一行的不同列访问就可以直接从行缓冲读取,速度更快。
- 灵敏放大器:在读出时放大存储单元微弱信号,同时在做刷新时把数据回写。
- 数据缓冲器:对外输出数据或接收写入数据。
我在教新人时常用一个比喻:DRAM芯片像一个超大的货架仓库,货架(行)一次只能拉一层下来到传送带(行缓冲),然后在传送带上取某箱货物(列)。 如果你碰巧连续要同一层的货,效率极高;如果要不同层的货,就得先推回去再拉新的一层,这个"拉货架"的动作就是行的预充电和激活,是需要付出时间代价的。
3. 从芯片到内存条:位扩展、字扩展和地址译码实战
3.1 位扩展:把窄芯片拼成宽数据通路
实际工程中,单片DRAM芯片的数据位宽通常达不到CPU数据总线宽度。比如CPU的数据总线是8位,但单个存储芯片只有1位数据线,怎么办?用8片1M×1位的芯片并联,每片各提供一位,就能组成1M×8位的内存。
这种扩展方式叫位扩展,特点是:存储单元总数(字数)不变,但每个地址对应的数据位宽变宽。连线的时候特别要注意:
- 地址线并联:8片芯片的地址引脚全部连到同一条地址总线。
- 数据线分接:每片芯片的数据引脚分别接到数据总线的D0、D1……D7。
- 控制线共用:读/写控制线、片选线全部连在一起。
所以位扩展的规则就一句话:8片芯片同时被选中,同时工作,各贡献一位。
3.2 字扩展:用片选信号决定谁干活
字扩展的方向完全不同。假设每个芯片还是1M×8位,但我们需要2M×8位的内存,怎么办?用2片容量相同的芯片,地址线、数据线都并联,区别在于每片芯片的片选信号(CS)必须分开接——系统通过高位地址译码决定哪个芯片被激活。
举个例子,地址总线有21位(A0~A20),但每片芯片只有20位地址线(A0~A19),那么最高的A20就成了"片选选择位":
- 当A20=0时,选中第一片芯片,访问地址范围 0x00000~0xFFFFF;
- 当A20=1时,选中第二片芯片,访问地址范围 0x100000~0x1FFFFF。
所以字扩展会增加存储深度(字数),不改变位宽,它靠片选信号做"分地盘"。
3.3 用74LS138做地址译码:经典到骨子里的设计
做字扩展时,片选信号的产生需要译码器。教科书上讲得最多的就是74LS138:3个输入选择端C、B、A,3个使能端,输出8路低电平有效的片选信号。用它做3-8译码器,正好可以把3根高位地址线的组合映射到8个芯片。
我记得本科做计算机组成实验时,刚接触这片子总踩一个坑:74LS138的输出是低电平有效,也就是输出端平时是高电平,选中某一路时才拉低。如果你把译码器输出直接接芯片的CS引脚,必须确认CS是低电平有效的那一种。很多新手拿着TTL芯片手册,没有确认有效电平,结果连出来的电路要么所有片都不工作,要么所有片同时被选中,一片乱象。
解决方式也很直观:查手册,确认片选脚是低有效还是高有效,然后决定译码输出直接接还是加反相器。
3.4 存储器与CPU的连接:时序、负载和总线的配合
芯片扩展的核心并不只是"能把芯片接上",还要满足CPU的时序要求。CPU访问存储器的过程大致是:
- CPU在地址总线上给出地址;
- CPU发出读命令,同时等待数据;
- 存储器译码、寻址、输出数据;
- CPU从数据总线上读取数据。
这中间涉及一个概念:存储器访问时间必须小于CPU的读周期。现代CPU和内存条之间有完整的时序握手(读响应、等待状态),但在简化的课程模型里,你必须确保每个环节延迟都在CPU可接受范围内。
实操中还要注意总线负载能力。一根地址线要同时驱动多片芯片,如果芯片输入电容过大、驱动电流不足,信号质量就会劣化。这也是为什么内存条上有那么多电阻终端匹配和驱动缓冲,电平信号在这条路上走几厘米和走几十厘米,完全不是一回事。
4. 数据在内存里会不会出错:奇偶校验和汉明码
4.1 奇偶校验:最基本也最容易被击穿
内存芯片工作在高速、高密度的环境里,软错误(粒子翻转、电压波动、信号串扰)很难完全避免。数据出错是常态,校验才是例外。
奇偶校验是最简单的检错方式:在有效数据位之外额外增加一个校验位,让整个数据中"1"的个数保持为奇数(奇校验)或偶数(偶校验)。接收方重新计算,如果发现奇偶性不对,就认定数据错误。
这个方法实现简单、硬件开销极小,但有两个致命问题:
- 只能检测奇数个位错误;如果两个位同时翻转,奇偶性不变,等于没检。
- 只能检错,不能纠错——你只知道数据坏了,不知道坏在哪个位上。
4.2 汉明码:不仅知道出错,还能揪出是谁错了
汉明码是《计算机组成原理》里不可回避的经典。它用多个校验位,覆盖不同的位分组,让每个校验位能"指认"一部分位,从而通过校验失败的模式定位到具体出错的位置,进而纠正它。
汉明码的编码规则:
- 校验位的位数k和有效数据位n之间满足:2^k ≥ n + k + 1。
- 校验位放在2的幂次位置上(第1、2、4、8……位)。
- 每个校验位负责覆盖一组特定的数据位——覆盖的规则是"二进制编号中某一位为1"的所有位置。
例如对4位数据d3d2d1d0编码为7位汉明码,校验位放在位置1、2、4,覆盖关系是:
- p1覆盖位置1、3、5、7(二进制最低位为1的位置)
- p2覆盖位置2、3、6、7(二进制的第二位为1的位置)
- p4覆盖位置4、5、6、7(二进制的第三位为1的位置)
如果接收时位置3、5、7的校验结果出错,而p2正确、p4正确,就能定位到位置3错误,然后直接翻转纠正。
汉明码的工程价值在于:它把"检查是否出错"升级为"出错时能自愈"。服务器内存条里的ECC(Error Correcting Code)内存用的就是类似思路——能检测并纠正单比特错误,检测双比特错误。云厂商卖的高配实例、数据库服务器物理机,ECC内存是标配,原因就在这里。
4.3 ECC内存对软件工程师意味着什么
如果软件跑在非ECC内存上,内存里一个比特静默翻转,程序可能没有任何感知,只是某次计算结果莫名其妙地错了。这种错误最难排查,因为它不是必现的、不是逻辑可推导的,而是随机的、瞬时性的。
我用ECC内存之后有个非常直观的感受:之前跑一个需要数小时的多机分析任务,偶尔会出现个别worker最终校验值不对的情况,查了很久找不到原因。后来给实验机器换装ECC内存后,这类问题从"隔三岔五"变成"从未出现"。这就是校验机制切切实实的价值。
5. 访存时序和现代内存:从SDRAM到DDR5
5.1 SDRAM为什么是"同步"的,时序参数又是怎么来的
SDRAM的出现是内存历史上的一次分水岭。早期异步DRAM的控制信号和CPU时钟没有严格对齐,访问周期的控制靠的是几个延时参数你来我往;而SDRAM(同步动态随机存取存储器)把所有操作都锁存到时钟上升沿,控制逻辑大幅简化,也为后来的流水线、突发传输创造了条件。
操作系统和BIOS里内存参数一堆花里胡哨的数字,核心就那些:
| 参数 | 全称 | 含义 | 对性能的影响 |
|---|---|---|---|
| CL | CAS Latency | 发出列地址到数据输出的延迟 | 越低越快 |
| tRCD | RAS to CAS Delay | 行激活到列访问的延迟 | 越低越快 |
| tRP | Row Precharge Time | 预充电结束到下次行激活的间隔 | 越低越快 |
| tRAS | Active to Precharge | 行最小激活时间 | 不能太短 |
这四个参数连起来,就是完整的一次读流程:tRCD(行激活)→ CL(列读出)→ 突发传输数据,最后tRP预充电关闭行。内存条上写的CL16、CL18指的就是列地址选通延迟,CL18会比CL16慢大约2个时钟周期。
5.2 突发传输和带宽计算:内存条的理论上限
现代DDR内存不会一次只传一个字节,它按"突发长度(Burst Length)"成批传输。比如DDR4的突发长度通常是8,也就是一次访问能连续输出8个64位数据(连读8个地址),极大摊薄了行激活和列选择的开销。
内存理论带宽的计算方式很简单,但很多人容易算错:
code复制内存带宽 = 工作频率 × 数据总线位宽 / 8
以DDR4-3200为例:
code复制DDR4-3200的核心频率=400MHz,但由于双倍数据速率(DDR),
有效数据传输率=400MHz×2=800MHz,又称传输速率=3200MT/s。
单通道位宽=64位=8字节,
所以每个通道的理论带宽=3200MT/s×8B=25.6GB/s。
这里特别值得注意的一个点是:型号里的3200是MT/s(兆次传输每秒),不是MHz。我见过太多人在理解"为什么DDR4-3200对应1600MHz但频率写着3200"的时候晕头转向,其实关键就在于DDR在时钟上升沿和下降沿都传输数据,所以传输速率是时钟频率的两倍。
5.3 双通道和矩阵布局:为什么内存条的排列方式有讲究
主板上支持双通道时,两个内存插槽分别连接到CPU内存控制器的不同通道。CPU可以同时对两个通道发起访问,所以理论上带宽翻倍。
但双通道不是随便插两根就一定能发挥出来,要满足几个条件:
- 两根内存条容量一致,且尽量同品牌同型号;
- 插在正确颜色的插槽上(很多主板会标注A1/B1或A2/B2配对槽位);
- 最好开启主板BIOS里的XMP(Extreme Memory Profile)或EXPO(AMD平台),让内存跑在标称速率而不是默认的保守速率。
我自己在装机时踩过不少次兼容性的坑:不同品牌的内存在默认时序上可能不同,强制开启XMP后系统不稳,轻则蓝屏,重则数据损坏。稳妥的做法是:要么全用同一套套条,要么只开XMP到内存条中较保守的那根规格。
5.4 内存模块的内部组织:Bank、Rank和通道
很多人以为内存条内部结构很简单,其实和SSD一样,也是一套并行体系。内存模块里按层次划分:
- Channel(通道):CPU到内存控制器的独立通路,一般CPU支持双通道或四通道。
- Rank(列组):一组DRAM芯片并行工作的集合,一个Rank共享数据总线。单Rank和双Rank的区别就是能不能同时激活更多芯片组。
- Bank(存储库):一个DRAM芯片内部划分的多个独立存储阵列,每个Bank可以独立执行行激活、预充电等操作,多个Bank交错工作可以隐藏延迟。
理解这几个概念,你就能看懂为什么"插满内存插槽不一定性能最好"——因为太多Rank和Bank在共享总线时也可能引入信号完整性问题,导致不得不降频运行。这也是服务器调优里常见的一个话题:四通道八插槽的机器,反而是插6根内存条性能更优,因为特殊插法能利用好交错和拓扑结构。
6. 从一块内存条到一台计算机:主存系统的完整视角
6.1 地址空间、映射和操作系统的介入
站在软件的角度,你写代码时操作的是虚拟地址,不是物理地址。CPU发出的地址要经过MMU(内存管理单元)的页表翻译,才能变成物理地址,然后通过内存控制器访问到具体的DRAM单元。
操作系统在这一层做了很多事:分页、缺页中断、内存分配、进程隔离。所以我们常说的"程序占了多少内存",实际映射的是虚拟地址空间占用,真实物理内存占用可能远小于这个数字——因为很多页面可能还没被访问、还没被加载到物理内存,甚至已经被换出到磁盘。理解这层映射关系后,你就明白为什么看task manager里进程的内存占用往往"虚高"。
6.2 程序性能与主存储器失配的经典场景
我遇到过好多真实案例,都是主存储器的特性直接决定了软件性能:
案例一:遍历大数组,行优先和列优先的巨大差异。 二维数组在C/C++里按行优先存储。当你按列遍历时,每次访问都在跨行跳内存地址,Cache命中率暴跌,程序可能慢10倍以上。这在本质上就是主存-Cache层次和局部性原理的较量。
案例二:锁的伪共享(False Sharing)。 多线程分别修改不同变量,但两个变量恰好落在同一个缓存行(Cache Line,通常64字节)里。每次某线程更新,会导致其他线程的缓存行失效,被迫重新从主存加载。表现就是并发程序性能不升反降。解决办法是缓存行填充——让不同线程的变量隔离开,不在同一个缓存行内。
案例三:内存分配器的高频小对象分配。 如果频繁new/delete小块内存,内存碎片和分配器锁会成为瓶颈。高级的内存池、对象池设计,本质上就是在替程序"预取"和"复用"主存资源,减少对操作系统的内存分配调用。
这些场景让我越来越确信:《计算机组成原理》主存储器这一章,不是背概念用的,它直接决定了软件怎么做性能优化方案。
6.3 主存储器面临的技术挑战与演进方向
主存储器在工程上还面临几个老大难问题:
- DRAM刷新带来的访问毛刺:由于要定期刷新,刷新期间的内存访问被阻塞。服务器场景可以用自适应刷新、刷新伪装等机制,缓解延迟抖动。
- 内存崩溃(Memory Scrubbing):ECC内存后台定期巡检、检测和校正潜在错误位,防止一个物理位故障慢慢发展成实际错误。这是服务器主流做法,但会占用一定的内存带宽。
- 近内存计算(Processing-in-Memory):把部分计算逻辑下沉到存储器件附近,减少数据搬运开销。这个方向研究很活跃,未来可能彻底改变现在的存储-计算分离架构。
- 新型非易失内存(如Intel Optane DC Persistent Memory):介于DRAM和SSD之间,断电不丢数据,但又可以按字节寻址。它改变了"内存断电即失"的基本假设,给数据库和文件系统带来了新的设计空间。
不过说实话,对于大多数做应用开发的工程师,这些前沿技术短期内并不需要直接上手。更重要的是把这篇讲的这些经典机制吃透,它们才是你现在每天面对的一切内存行为的底层解释。
7. 学习路径和常见误区:给正在啃这一章的人的真心建议
7.1 先动手做实验,再回头啃概念
我的建议是先别急着背术语。把实验课上的存储芯片扩展、译码器连接、甚至用一个简单的逻辑仿真器搭建一个8×4位的内存模块,亲眼看清楚地址怎么译码、数据怎么进出、片选怎么工作。手摸过一遍之后,再看课本上那些"DRAM刷新周期""位扩展字扩展"的定义,完全就是水到渠成的事。
如果你现在没有实验条件,也有替代方案:用Python或C语言写一个简易内存模拟器,定义存储阵列、地址译码、读写时序,逼真地模拟一次CPU取指过程。做一次这种小项目,比反复看书要高效得多。
7.2 真题和考试视角:这道题到底在考什么
很多备考同学会问,《计算机组成原理》里主存储器这一章考试重点在哪。从历年的408和考研真题来看,重复率最高的几个点:
- 存储容量计算和芯片扩展:给一个内存总容量,加上给定的单芯片规格,求需要多少片芯片、怎么连接;
- 地址线和数据线的计算:比如1M×8位芯片,地址线是20根(2^20=1M),数据线8根;
- 刷新相关的计算:给定DRAM行列数、刷新周期,求刷新开销;
- Cache的映射方式:直接映射、全相联、组相联,计算Cache容量、标记位、索引位数;
- 汉明码的编码和纠错:给定数据位,写出汉明码并验证纠错。
这部分的窍门就是把推演过程写清楚,不要直接背答案。比如扩展题目,动笔之前先把"位数"和"字数"两大维度拆开,然后确认是位扩展还是字扩展,再开始连线,正确率就会高很多。
7.3 软件工程师最值得额外关注的三个细节
如果你是软件背景的同学,我建议在学主存储器时多注意这几个细节,它们将来会让你在很多场景下少踩坑:
- 字节序(Byte Ordering):x86是小端存储(低位字节在低地址),网络协议是大端(高位字节在低地址)。这个看似基础的知识,跨语言跨平台传数据时经常坑人。
- 内存对齐(Memory Alignment):CPU按字访问内存,如果数据没有对齐,一次访问可能拆成多次,性能下降甚至某些平台直接报错。结构体里字段顺序和填充规则,就是主存访问粒度在软件层面的投影。
- Cache友好的编码习惯:循环嵌套时把最内层循环放在连续地址维;多线程共享数据时注意避免伪共享。这些习惯一旦养成,写出来的程序在真实机器上表现会明显更稳。
7.4 遇到"内存不懂"时的排查思路
最后分享一个实用的排查套路。如果你发现程序性能奇怪、有偶发性错误,可以按这个顺序排查内存相关问题:
- 用ECC内存、跑内存自检工具(如MemTest86)确认硬件层面没有静默错误;
- 检查是否有Cache未命中率异常高——用性能分析工具(perf、VTune)看Cache Miss;
- 检查是否有伪共享——看缓存行冲突,必要时用填充结构体字段解决;
- 检查是否有内存碎片和高频分配——用内存分析工具(Valgrind massif、jemalloc profile);
- 检查是否被其他资源挤占——NUMA架构下内存访问还有"远端/本地内存"的延迟差异,线程绑核和内存绑核配合不好也会带来额外延迟。
我自己的体会是,很多看似CPU密集型的问题,真正的瓶颈其实在内存层级上。CPU计算再快,数据搬不到位也是白搭。主存这一层,决定了数据搬运的下限。
你现在学的主存储器,不只是为了期末考试、不是为了应付一场面试,它会在将来你用perf看火焰图、用profiler排查性能瓶颈、设计高并发低延迟系统时,回过头来一次次帮你找到那只"看不见的手"。我到现在还会偶尔翻翻当年的课堂笔记,每次都有新的收获。
如果你正在啃这一章,别急,把SRAM和DRAM的区别、芯片扩展、校验机制、访存时序这四个支柱先立起来,后面的路就好走了。把这篇文章收藏起来,学习过程中遇到具体问题时,随时回来对照着看。
