1.计算机电脑单元架构

计算机是由几个单元所组成的,包括输入单元、 输出单元、CPU 内部的控制单元、算数逻辑单元与内存五大部分。

  • intel 主板典型架构如下

  • 北桥负责链接速度较快的CPU、内存与显卡接口等元件北桥最重要的就是 CPU 与内存之间的桥接,因此目前的主流架构中, 大多将北桥内存控制器整合到 CPU 封装当中了。所以上图只看到 CPU 而没有看到以往的北桥芯片。

  • 南桥负责连接速度较慢的设备接口, 包括硬盘、USB、网卡等等。

2.CPU 简介

Central Processing Unit 中央处理器,作为计算机系统的运算和控制核心,是信息处理、程序运行的最终执行单元。

  • CPU核心:一般一个CPU会有多个CPU核心,平常说的多核是指在一枚处理器中集成两个或多个完整的计算引擎。核跟CPU的关系是:核属于CPU的一部分。
  • 寄存器:最靠近CPU对存储单元,32位CPU寄存器可存储4字节,64位寄存器可存储8字节。寄存器访问速度一般是半个CPU时钟周期,属于纳秒级别,
  • L1缓存:每个CPU核心都有,用来缓存数据跟指令,访问空间大小一般在32~256KB,访问速度一般是2~4个CPU时钟周期。
    cat /sys/devices/system/cpu/cpu0/cache/index0/size # L1 数据缓存
    cat /sys/devices/system/cpu/cpu0/cache/index1/size # L1 指令缓存
  • L2缓存:每个CPU核心都有,访问空间大小在128KB~2MB,访问速度一般是10~20个CPU时钟周期。
    cat /sys/devices/system/cpu/cpu0/cache/index2/size # L2 缓存容量大小
  • L3缓存:多个CPU核心共用,访问空间大小在2MB~64MB,访问速度一般是20~60个CPU时钟周期。
    cat /sys/devices/system/cpu/cpu0/cache/index3/size # L3 缓存容量大小
  • 访问数据顺序:CPU在拿数据处理的时候几乎也是按照上面说得流程来操纵的,只有上面一层找不到才会找下一层。
  • Cache Line : CPU读取数据时会按照 Cache Line 方式把数据加载到缓存中,每个Cacheline = 64KB,因为L1、L2是每个核独有到可能会触发伪共享,就是 所以可能会将数据划分到不同到CacheLine中来避免伪共享,比如在JDK8 新增加的 LongAdder 就涉及到此知识点。
  • 如上图所示,CPU访问速度是逐步变慢,所以CPU访问数据时需尽量在距离CPU近的高速缓存区访问。

3.内存 简介

  • 内存:多个CPU共用,现在一般是4G~512G,访问速度一般是200~300个CPU时钟周期。

关于可以参考以下连接:【高速PCB电路设计】8.DDR模块设计实战

  • 操作系统主要采用内存分段和内存分页来管理虚拟地址与物理地址之间的关系,其中分段是很早前的方法了,现在大部分用的是分页,不过分页也不是完全的分页,是在分段的基础上再分页。

  • 如上图的JVM内存模型举例,程序员会认为我们的代码是由代码段、数据段、栈段、堆段组成。不同的段是有不同的属性的,用户并不关心这些元素所在内存的位置,而分段就是支持这种用户视图的内存管理方案。逻辑地址空间是由一组段构成。每个段都有名称和长度。地址指定了段名称和段内偏移。因此用户段编号和段偏移来指定不同属性的地址。而虚拟内存地址跟物理内存地址中间是通过段表进行映射的。

内存分段管理:

  • 如上虚拟地址有 5 个段,各段按如图所示来存储。每个段都在段表中有一个条目,它包括段在物理内存内的开始的基地址和该段的界限长度。例如段 2 为 400 字节长,开始于位置 4300。因此对段 2 字节 53 的引用映射成位置 4300 + 53 = 4353。对段 3 字节 852 的引用映射成位置 3200 + 852 = 4052。

  • 分段映射很简单,但是会导致内存碎片跟内存交互效率低。这里先普及下在内存管理中主要有内部内存碎片跟外部内存碎片。

  • 内部碎片:已经被分配出去的的内存空间不经常使用,并且分配出去的内存空间大于请求所需的内存空间。

  • 外部碎片:指可用空间还没有分配出去,但是可用空间由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。

  • 以上图为例,现在系统空闲是1400 + 800 + 600 = 2800。那如果有个程序想要连续的使用2000,内存分段模式下提供不了啊!上述三个是外部内存碎片。当然可以使用系统的Swap空间(如下图),先把段0写入到磁盘,然后再重新给段0分配空间。这样可以实现最终可用,可是但凡涉及到磁盘读写就会导致内存交互效率低。


内存分页:

  • 内存分页,整个虚拟内存和物理内存切成一段段固定尺寸的大小。每个固定大小的尺寸称之为页Page,在 Linux 系统中Page = 4KB。然后虚拟内存跟物理内存之间通过页表来实现映射。

  • 采用内存分页时内存的释放跟使用都是以页为单位的,也就不会产生内存碎片了。当空间还不够时根据操作系统调度算法,可能将最少用的内存页面 swap-out换出到磁盘,用时候再swap-in换入,尽可能的减少磁盘刷写量,提高内存交互效率。

  • 分页模式下虚拟地址主要有页号跟页内偏移量两部分组成。通过页号查询页表找到物理内存地址,然后再配合页内偏移量就找到了真正的物理内存地址。

  • 32位操作系统环境下进程可操作的虚拟地址是4GB,假设一个虚拟页大小为4KB,那需要4GB/4KB = 2^20 个页信息。一行页表记录为4字节,2^20等价于4MB页表存储信息。

  • 多级页表、段页式管理在此暂不赘述。

Linux 内存管理

  • Linux系统基于X86 CPU 而做的操作系统,所以也是用的段页式内存管理方式。

  • 我们知道32位的操作系统可寻址范围是4G,操作系统会将4G的可访问内存空间分为用户空间跟内核空间。

  • 内核空间:操作系统内核访问的区域,独立于普通的应用程序,是受保护的内存空间。内核态下CPU可执行任何指令,可自由访问任何有效地址。

  • 用户空间:普通应用程序可访问的内存区域。被执行代码会受到CPU众多限制,进程只能访问映射其地址空间的页表项中规定的在用户态下可访问页面的虚拟地址。
    那为啥要搞俩空间呢” />
    磁头:做径向运动——沿着半径来回运动,轨迹是固定的。
    盘片:做圆周运动——就像DVD的光盘一样的转动。
    可以想象下,只要通过这两者的运动,就可以定位到光盘的任何一块,数据是存在盘片上的,磁头则负责写和读。

    参考资料:
    参考1: [鸟哥的Linux私房菜-基础学习 第四版]
    参考2: 硬核操作系统讲解—-计算机架构部分
    参考3: 磁盘读写数据原理