还有说实话每次看到这样鼓吹 C 的言论,感觉很 low 。老是说底层底层,不知道是不是自己脑补还是怎么啦。动不动来句 “底层”,要真说底层,估计一句话也答不上来。这种感觉让我想起了亲身经历的事。隔壁寝室有一同学( CS 毕业了找不到工作送中通),然而他大三时,我亲耳听到他向大一学弟吹嘘 C/C++ 如何如何好,如何接近底层(虽然我不反对他的说法,但我一脸鄙视)。
而且我还想吐嘈,每次有人问如何学习计算机,就有人列一大堆课本。我怀疑发这贴的人,有多少人是认真看过的。
题外话,你仍然想学习底层,那学习底层最好的方法,当然是直接学习底层。指令集架构,微架构,数电,模电,一层层看呗,有兴趣的话。一步步歪下去的话搞不好会转专业哦(和我一样, CS 转 EE 的奇葩)。这种情况下, C 搭着学一学,可以,比较大部分这方面的代码都用 C 。但如果只学 C 那点东西,指望能怎么 “底层”,那是不可能的。而且如果是考虑程序员这个职业,那自然更没必要。
(虽然我平时要说也基本只用 C 。混着汇编和机器码吧。还有 bash 做胶水。描述语言不算。我是搞硬件的, CPU )。
@
bramblex 地址,你就拿邮编做比方。只不过计算机是二进制,门牌是十进制;计算机以字节为单位,邮编以社区为单位。
要精确到内存上... long story...
就说 pc 的 dimm ,比如我前阵子在调的这个(普通笔记本用)内存条。双面各 8 个芯片(共 16 个, 64Mx8-bit );上面的 8 片的 cs 连在一起,和下面的 8 片的 cs 连在一起,组成两个 rank ; 8 片 8-bit dq (双向数据线)按位扩展到 64-bit ,一起和地址 /控制线接到内存控制器上。 dram 芯片上,有 4 个 bank ,每个 bank 有 16k row ,每个 row 1k column ,每次读写可选 4/8 长度的 burst 。要访问,需要先 active , read/write , precharge 三个阶段。可利用的地方比如,不同的 bank 可同时处于 open 状态(即不被 precharge ),而且如果处于 open 状态只要处在同一个 row 里可以快速访问(否则必须 precharge 关掉再 active )。另外至多每隔 64 ms 必须 refresh , refresh 后需要重新 active 。(说得有些不清楚,感兴趣的可以看 JEDEC 文档或内存芯片的文档)这样给内存控制器很多设计空间了。举例,比如是保持 open ( open-row policy )这样可减小同 row 的访问延迟,但是其他 row 的延迟会增大,而且 open 会更耗电,也有一些其他的限制;还有一种是 close-row policy ,延迟可能会大,但功耗小;当然有动态调节的,看情况。还有不同通道独享总线互不影响。(程序员应该都知道 locality )以上各种原因决定了物理地址到 channel/rank/bank/column/row 的映射。
到 CPU 里面(现在应该都是集成了内存控制器)。内存控制器挂在 coherent interconnect 下面,上面是 cpu 最后一级缓存。哎感觉说了半天也没说清楚,不说了。反正 the rest is history , cache controller, line fill buffer,
eviction buffer, snoop filter, tlb/itlb/dtlb, page walker (虚实地址转换就是前面几个货在弄), load/store queue, etc. etc.
如果你知道你程序里变量的虚拟地址( C 里的 & 操作),页在内存里,能 dump 出页表,知道能 flush cache all the way to DDR ,知道内存控制器的设计和设置,知道你内存条的配置,理论上来说,你应该能精确到在哪颗 DDR 颗粒里(如果有内存条的 RTL 和 GDSII ,也许你能够知道具体在哪里)