RAM

你。 提交于 2019-11-26 20:02:02

1.     前记

我们知道,不同的计算机结构对RAM 的使用方式是有区别的,典型的计算机结构有两个,冯诺依曼结构和哈佛结构,而两大阵营的领军人物就是传说中的Intel X86系列的8086和51单片机系列的8051。请先对号入座,不理解的跳过去,继续往下看。

2.     What?

长啥样?

 

内存条,RAM中的一种,常见的应该是DDR SDRAM。相信各位都触摸过它,冷冰,无情,当然,你上电后它就变了样,暖暖的,无怨无悔的为我们干活。

 

嘿!别唬我,这个俺知道,51单片机。没错,51单片机里面也内置了RAM ,叫片内RAM。

 

这个就是一般嵌入式板卡上的RAM, 为了加以区分,就叫片外RAM。

广义上讲,CPU内部的寄存器也算是RAM的一种。

在哪里?

PC主板图片

 

嵌入式板卡图片

 

找一找你系统上的内存吧,再看看CPU datasheet 上有没有提到内置RAM。

特点是啥?

RAM(Random Access Memory),随机存储器。特点如下:

  • 如其名,可随时读写
  • 快,读写速度杠杠的,CPU最喜欢和它一起“玩”了
  • 掉电后,数据全部丢失,因此,别指望RAM中的数据长期存储,那么,我想要长期存储公司所有员工的数据怎么办?用FLASH吧。

请参考:

RAM、ROM、Flash的分类、性能比较

RAM,ROM,FLASH存储器区别

 

与CPU的连接方式

RAM是用来存储CPU计算所需的数据的,那么它怎么与CPU进行通话呢。就是通过那个叫做大巴士(Bus)的东东了,所有数据都是坐着大巴士在CPU和RAM 之间飘过来,再飘过去的。

 

3.     Why?

RAM特点决定了它的应用,保存计算过程中的数据。什么?不理解,举个例子,我想知道1+2等于多少?条件,写个程序,这活儿让必须由CPU干,看看过程:

  • CPU向RAM单元里“写入”两个操作数1和2(“写入”过程先飘过)
  • CPU从RAM指定单元中“读取”操作数1,操作数2,和运算指令“+”(“读取”过程也先飘过吧)
  • CPU解析读取的指令
  • CPU执行计算,给出结果3

执行过程中的“1”“2”“+”就是存储在RAM中的(当然可以用更简单的方法实现),执行完后,RAM中数据就没有存在的意义了,可以去干2+3等其他活了。这么简单的活儿当然没有必要CPU来完成,但是,如果领导非要你去确认一下1+1计算4294967295次这个“哲学”问题的结果的话,总不能找个小本本自己蛮干吧。看着就头大,可工作吗,总不能有情绪啊。

写个程序,扔给计算机,这哥们可是位任劳任怨的好公仆,喝杯茶,你就可以认真负责的交差啦。

好了,现在我们知道CPU虽然是个好同志,可是总有忙不过来的时候,那就请个秘书(存储器)帮忙吧!我们的存储器有很多种,寄存器,RAM系列,ROM系列,flash系列,还有硬盘,USB,SD卡(这哥仨比较特殊,请先记住,他们可读可写,掉电后数据不会丢失,先归到FLASH系列吧)等等。

那么,为什么CPU会选择RAM呢?我们先聊聊其他的。

为什么不是寄存器呢?前面提到过寄存器也是一种RAM,而且读写速度比片外的RAM还快。但是,寄存器是内嵌在CPU内部的,CPU就那么大点儿,能够内嵌的寄存器就那么几个,有的还有特殊用途,不能随便玩,仅用这几个存储单元,对CPU进行的复杂运算就无能为力了。

为什么不是ROM呢?从其特点看,这玩意儿相当稳定,Read Only嘛,轻易改变不了上面的内容,这也是为什么很多嵌入式系统将代码烧到ROM的原因了,随你风吹雨打,我自岿然不动。但是,你只让CPU看,不让CPU摸,CPU怎么把中间结果暂存到里面呢?

为什么不是FLASH呢?FLASH是可读可写的,这点与RAM没区别。但是,FLASH的写比较麻烦,不能直接写,只能先把原来的内容擦干净。CPU也是嫌麻烦的,多出来的擦过程意味着,CPU干正常活的时间变少了。不爽。还有,FLASH的读写是以块为单位的(NOR FLASH 块大小64~128KB,NAND FLASH块大小,8~32KB),这可不行啊,我就想用一个字节,影响太大了。而且,FLASH写入擦除速度也不敢恭维(NOR FLASH ,5s;NAND FLASH,4ms)。

再看看RAM吧,速度,价格,好而不贵,这里需要掌声!

种类

速度

单位存储价格

寄存器

 

 

ROM

 

 

NAND FLASH(FLASH)

 

 

SDROM(RAM)

 

 

CPU

 

 

上面的数据是同一板卡上各芯片的数据,因为技术发展得太快,不同时期的比较没有参考意义。

CPU在找“秘书”的时候郁闷了,Why?Why?Why there is always a “但是”,肿么办?看看价格,再看看速度,其他的东西都不理想,好吧,就是你了,瞎看什么,说你呢内存。

CPU选择存储器,这过程有点儿像“木桶”现象,CPU速度往往很快,因此,制约系统速度的那个短板就是存储器了。而随着技术的发展,单位存储的成本也在不断下降,相信,总有一天,现有存储器的区别将不再这样明晰,继而,从这个世界消失。一切只是时间而已。

4.     HOW?

CPU搭讪RAM

我们知道CPU和RAM是一对好基友。那么,CPU总得主动去搭讪吧。

存储器内部被划分为一个个的小格格,并且从0开始编号,例如,内存的容量是64K,那么就有64*1024个小格格啦。每个小格格可以用来读写1、2、3等等的数据。CPU如何操作呢?还记得大巴士嘛。三步走:

  • CPU通过地址总线,向存储器发送指令的地址信息
  • CPU通过控制总线,向存储器发送控制信息(读OR写)
  • CPU通过数据总线,从存储器读取数据或向存储器写入数据

我们来看看CPU从3号单元中读取数据的过程。(摘自:《汇编语言》)

 

  • CPU通过地址总线将地址信息3发出,我们可以看到,地址信息3就乘着巴士飘向RAM了
  • CPU通过控制总线发出读取命令,我们可以看到,“读取”信息乘着巴士也飘香RAM了
  • 存取器将3号单元中的数据8通过数据总线传回CPU,我们可以看到,数据信息8乘着数据巴士飘向CPU了。

是CODE还是DATA?

我们知道了CPU如何从RAM获取数据。那么CPU从存储器上得到数据后,这个数据是指令还是数据呢,如何区分呢?

其实,在存储器内部,指令和数据没有任何区别,都是二进制信息。CPU在发送读取命令前,会先明确,收到的数据是指令还是数据(CPU的主观想法),换句话说,CPU在读取数据前,告诉自己,收到的这个数据将作为指令,收到数据后,就把该数据解析为指令,并存储在CPU的指令缓存器中;如果在读取数据前,告诉自己,收到的数据将作为数据,那么,收到数据后,就把该数据解析为数据,存储到指定的寄存器中。

例如,存储器中的二进制信息1000100111011000,计算机可以把它看做大小为89D8H的数据来处理,也可以将其看做指令mov ax,bx来执行。

1000100111011000→89D8H(数据)

1000100111011000→mov ax,bx(指令)

CPU是怎么工作的?

请参考《汇编语言》 第2.10节 CS和IP

画图解释1+2过程,注意应该使用SS,SP,PUSH,POP。

传奇的冯诺依曼结构计算机

冯·诺依曼结构,又称为普林斯顿体系结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。取指令和取操作数都在同一总线上,通过分时复用的方式进行。不理解???来,看图解释(Intel 8086 CPU)。

 

8086是16位结构的CPU,它的寻址能力是216=64KB(补充,其实8086的地址总线是20位的,也就是说最大的地址范围是220=1MB,但是由于16位CPU一次只能处理16位数据,所以才是64KB的寻址范围,可见,总有拖后腿的~)。

冯氏结构认为,读取指令和数据并没有区别,所以虽然所有的存取器在物理上是独立的,但CPU对他们进行统一编号,在它眼里只有一个逻辑存储器。为什么这么搞?简单啊,CPU只要记住各段地址映射到哪个物理存储器就好了,然后就是发重复的读写命令就OK!

上图中虚拟内存空间各段地址分配如下:

地址0000H~7FFFH的32KB空间:指向内存条(RAM)

地址8000H~9FFFH的8KB空间:指向显存

地址A000H~FFFFH的24KB空间:指向各个ROM的地址

其实,冯氏结构还有一个好处, CPU封装简单,通俗讲就是管脚少,因为和所有存取器连接的地址总线,数据总线,控制总线是共用的。试想,如果CPU与每个存储芯片都有一套独立的地址总线,数据总线,控制总线,那么要想访问所有存储器芯片,CPU引脚最多将是现在的N(N为存储器个数)倍。

目前使用冯氏结构的CPU和微控制器有很多。其中包括英特尔公司的8086及其他CPU,TI的MSP430处理器,ARM公司的ARM7,MIPS公司的MIPS处理器。

怎么又冒出来个哈佛结构计算机?

按冯氏结构的构想,读指令和读数据的操作是分时复用的,但,这里有个严重问题,就是“读指令”的时候,“读数据”就得等着,“读数据”的时候,“读指令”的操作也得先等着。在通用计算机(PC机)上没有问题,但是对于一些像数字信号处理这样的应用来说,这是致命的问题。怎么办?好办,指令和数据分开就可以喽。下面是哈佛结构。

 

如图,哈佛结构的计算机由CPU、程序存储器(ROM或FLASH)和数据存储器(RAM)组成,程序存储器和数据存储器采用不同的总线,从而提供了较大的存储器带宽,使数据的移动和交换更加方便,尤其提供了较高的数字信号处理性能。

目前使用哈佛结构的中央处理器和微控制器有很多,除了Microchip公司的PIC系列芯片,还有摩托罗拉公司的MC68系列、Zilog公司的Z8系列、ATMEL公司的AVR系列和安谋公司的ARM9、ARM10和ARM11。

为什么很多嵌入式系统采用哈佛结构?除了指令的读取速度,还有一个重要因素要考虑的:稳定。下面是常见的场景:

我们的Windows电脑死机后:骂娘,重启,还没听说过有人去找微软理论吧~

我们的嵌入式系统死机后:停产,而且,这是会使人的…

为什么会死机呢?其实很多时候是我们的“不小心”,操作数据的时候不小心把指令改掉了,而如果程序和数据分开存储呢,系统会稳定很多。

参考:冯诺依曼、哈佛、RISC、CISC

1+2=?再算一遍

我们先这样假设,我们计算的程序代码(CODE)是“1+2=?”数据是(DATA)“1”“2”。(当然,这样的假设并不严谨,只是这样更便于理解)

典型冯氏结构,1+2执行过程:执行前,CODE+DATA就是一个文件,其实就是一个EXE文件,存储在硬盘里。当我们双击这个文件时,CPU将硬盘中的CODE+DATA拷贝到RAM中,并指向第一个指令,CPU开始执行。想想我们在Windows上打开Notepad.exe的过程吧,查看你的内存使用量是不是突然增加了一小块,因为Notepad.exe是要被拷贝到RAM中才可以执行的。

典型哈佛结构,1+2执行过程:上电前,CODE+DATA就是一个文件,通常叫做Firm,被烧写到ROM或FLASH中,上电后,CODE部分不动,CPU将ROM中的DATA部分拷贝到RAM中,此时,程序存储器(ROM或FLASH)中存储CODE,RAM中存储着DATA,此后,CPU分别读取CODE和DATA,在CPU内部去执行读取到的指令。

注意,我们这里说的是都是“典型”结构,因为现在2015年,嵌入式系统为了提高读取指令的速度,也会把所有的CODE+DATA拷贝的RAM中执行,毕竟,RAM的读取速度比ROM和FLASH都快嘛,这样的哈氏结构就有点儿像冯氏结构了。另一方面,Intel X86系列的CPU内部加入了指令和数据缓存,从效果看,已经可以同时读取指令和数据了,这样的冯氏结构,又有点儿像哈氏结构了。

因而目前大部分计算机体系都是CPU内部的哈氏结构+CPU外部的冯氏结构。这样各取所长,达到了一个平衡。

CODE在哪儿?

从上面的讨论中,我们可以知道,这个问题是要看计算机状态的。

 

典型冯氏结构

典型哈氏结构

运行前

硬盘,想想咱们的应用程序是不是在某个磁盘下。确切的说,是EXE文件中的CODE部分。

ROM或FLASH中的CODE部分

运行时

RAM里,是由CPU从硬盘里拷贝过来的

ROM或FLASH中的CODE部分

DATA在哪儿?

与CODE一样,这个问题是要看计算机状态的。

 

典型冯氏结构

典型哈氏结构

运行前

硬盘,想想咱们的应用程序是不是在某个磁盘下。确切的说,是EXE文件中的DATA部分。

ROM或FLASH中的DATA部分

运行时

RAM里,是由CPU从硬盘里拷贝过来的

ROM或FLASH中的DATA部分

RAM全干了什么?

RAM是一种存储器,它的作用当然是存储数据了。我们来看看RAM到底可以存储哪些数据。

  • 存储计算的过程数据,我们可以这样理解,在C语言中声明的临时变量就在这里,如1+2=?中的1和2
  • 存储常量数据,这些数据是不变的,比如软件的版本号信息
  • 存储程序代码,前提是,程序运行时才会将程序代码拷贝到RAM中,程序关闭后被释放
  • 存储内核代码(就是传说中的操作系统了),开机时,从ROM或FLASH中拷贝到RAM中,并长期驻留在RAM中,直到关机

 RAM内部细分?

先看图:

 

由上面的讨论RAM的作用可以知道,内存可以按功能来细分,各个系统的叫法是有一点点儿区别的,请注意区分:

  • 代码区:简单的嵌入式系统,这个区只有类似1+2=?这样的代码。然而,像Windows和Linux这种含有操作系统的计算机,这个区包含内核代码和应用程序代码的。
  • 数据区:应用程序使用的数据,这个是可以再细分的
  • 堆栈区:这个单独聊

请谨记,这里所说的细分,只是我们使用内存的一种方法,本质上它仍然只负责存储数据,这样区分,只是概念性的。

堆栈

说起这个,得用一火车的话…

没有火车怎么办?简单聊。

目前为止,我们已经知道堆栈是RAM的一部分,他们依然是用于存储数据的,而且是人为划分的,那么,来看看他们的不同点吧。

 

栈(stack)

堆(heap)

谁分配的?

编译器和操作系统

编译器和操作系统

分配多大?

由你的程序决定,程序编译完后,大小就固定了

由你的程序决定。一支程序编译完后,CODE,DATA,STACK都是固定的,理论上其他的RAM都可以是Heap

分配的依据是什么?

MAP文件里记录了Stack的起始结束地址

你的程序里有没有malloc和new

有何用?

存储局部变量,参数

何时用?

函数调用时

申请未知大小的空间

怎么用?

代码中的声明的局部变量,在调用时都会入栈

主动申请:malloc和new

主动释放:free和delete

何时开始?

程序运行时

程序运行时AND程序主动申请

何时结束?

程序结束时

程序主动释放OR程序结束时

请参考:

What and where are the stack and heap? 里面干货很多,好好读读吧

什么是堆和栈,它们在哪儿? 如果你实在懒得不行,看看这个,是上文的不完整翻译

一只程序有多大?为什么?

这里指的是,PC上的EXE文件,嵌入式的FIRM文件大小。前面我们讨论过,你的程序中CODE,DATA, STACT大小是固定的,而且是编译后就决定了,因此你的程序大小由你程序中使用的CODE,DATA, STACT大小决定。

一只程序可用内存多大?为什么?

这个还用问吗?当然是RAM有多大就可以用多大。这在嵌入式系统中没有问题,你有一片128MB的RAM,自然就拥有了128MB的使用权。但在PC上你不觉得奇怪吗?假设你的PC上安装的是Windows7 32-bit OS,插着一条4GB的内存条,那理论上,最大的RAM寻址空间是232=4GB,你安装了Office2010。

我们来这样操作一下,打开一个Word文档,我们可以肯定,Word可用的RAM是这个内存条的4GB空间。我们再打开一个Excel文档,Excel可用的RAM是多少?答案是:理论上也可以有4GB。

为什么?现在的操作系统都支持多进程(Windows和Linux都支持),每个应用程序就是一个进程,对于一个进程而言,进程独享整个内存。其实,操作系统搞了个虚拟内存的东东,我们说内存独享整个内存,是指独享整个虚拟内存(虚拟内存会保持与物理内存的映射关系)。为什么这么干?每个程序(进程)是可能占用很大内存的,为什么说可能呢,因为Heap的动态变化。而通常情况下,这支程序(进程)内存的占有量并不大,过百M的程序已经算是内存大户了。如果进程占用整个物理内存,别的进程就别玩了。

所以,现在的策略是每个进程独享虚拟内存,多个虚拟内存共享物理内存,这样,大家就可以一起快乐的玩耍啦!

请参考:

Linux内存点滴 用户进程内存空间

Linux 虚拟内存和物理内存的理解

程序(进程)内存分布 解析

Linux 内存映射函数 mmap()函数详解

 MAP文件作用

查查你的MAP文件就知道了,它是记录你的程序,在RAM上的地址信息的。

5.     后记

我们回到原点,回答问题。

WHAT:RAM是个读写速度很快的存储器;

WHY:从速度和成本考虑RAM最适合于与CPU协同工作;

HOW:不同的计算机结构对RAM的使用方式是不同的。

不同系统往往要考虑两件事:成本,速度。从上面的讨论中可以看出,每个体统在选择芯片以及结构的时候,都在权衡这两件事,只是侧重点不同而已。记住,这两个不是东西的东西很重要,它们最终决定了你的系统的样子。

6.     参考文章:

. 汇编语言 王爽 第二版

. RAM、ROM、Flash的分类、性能比较

. RAM,ROM,FLASH存储器区别

. 单片机下程序 RAM, ROM ,Flash

. ARM中的Flash和RAM

. What and where are the stack and heap?

. 程序运行时是在flash中还是在RAM

. 单片机程序程序存储空间(ROM)和数据存储空间(RAM)详解

. 什么是堆和栈,它们在哪儿?

. C语言内存分布图

. 32位系统最大只能支持4GB内存之由来

. 深入Linux启动流程

. 冯诺依曼、哈佛、RISC、CISC

. 普林斯顿结构 VS 哈佛结构

. 关于冯诺依曼结构、哈佛结构、增强型的哈佛结构

. 程序(进程)内存分布 解析

. Linux 内存映射函数 mmap()函数详解

. Linux 虚拟内存和物理内存的理解

. Linux内存点滴 用户进程内存空间

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!