内存原理问题,这是一款MT41Jmt47h128m168内存芯片,列地址译码器为什么分两部分。分出去的Columns0,1,2做什么用

博客访问: 259051
博文数量: 74
博客积分: 587
博客等级: 中士
技术积分: 720
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
如何查看进程发生缺页中断的次数?
1、进程启动的时候,其(虚拟)内存空间的初始布局如图1所示。
&&&&& 其中,mmap内存映射文件是在堆和栈的中间(例如libc-2.2.93.so,其它数据文件等),为了简单起见,省略了内存映射文件。
&&&&&&_edata指针(glibc里面定义)指向数据段的最高地址。&
2、进程调用A=malloc(30K)以后,内存空间如图2:
&&&&&&malloc函数会调用brk系统调用,将_edata指针往高地址推30K,就完成虚拟内存分配。
&&&&& 你可能会问:只要把_edata+30K就完成内存分配了?
&&&&&&事实是这样的,_edata+30K只是完成虚拟地址的分配,A这块内存现在还是没有物理页与之对应的,等到进程第一次读写A这块内存的时候,发生缺页中断,这个时候,内核才分配A这块内存对应的物理页。也就是说,如果用malloc分配了A这块内容,然后从来不访问它,那么,A对应的物理页是不会被分配的。&
3、进程调用B=malloc(40K)以后,内存空间如图3。
情况二、malloc大于128k的内存,使用mmap分配内存,在堆和栈之间找一块空闲内存分配(对应独立内存,而且初始化为0),如下图:
4、进程调用C=malloc(200K)以后,内存空间如图4:
&&&&&&默认情况下,malloc函数分配内存,如果请求内存大于128K(可由M_MMAP_THRESHOLD选项调节),那就不是去推_edata指针了,而是利用mmap系统调用,从堆和栈的中间分配一块虚拟内存。
&&&&& 这样子做主要是因为::
&&&&&&brk分配的内存需要等到高地址内存释放以后才能释放(例如,在B释放之前,A是不可能释放的,这就是内存碎片产生的原因,什么时候紧缩看下面),而mmap分配的内存可以单独释放。
&&&&&&当然,还有其它的好处,也有坏处,再具体下去,有兴趣的同学可以去看glibc里面malloc的代码了。&
5、进程调用D=malloc(100K)以后,内存空间如图5;
6、进程调用free(C)以后,C对应的虚拟内存和物理内存一起释放。
7、进程调用free(B)以后,如图7所示:
&&&&&&& B对应的虚拟内存和物理内存都没有释放,因为只有一个_edata指针,如果往回推,那么D这块内存怎么办呢?
当然,B这块内存,是可以重用的,如果这个时候再来一个40K的请求,那么malloc很可能就把B这块内存返回回去了。&
8、进程调用free(D)以后,如图8所示:
&&&&&&& B和D连接起来,变成一块140K的空闲内存。
9、默认情况下:
&&&&&& 当最高地址空间的空闲内存超过128K(可由M_TRIM_THRESHOLD选项调节)时,执行内存紧缩操作(trim)。在上一个步骤free的时候,发现最高地址空闲内存超过128K,于是内存紧缩,变成图9所示。
阅读(1368) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。存储器系统 微机原理 第2版 课后答案_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
存储器系统 微机原理 第2版 课后答案
上传于||暂无简介
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩9页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢内存技术(5)
内存最基本的单位是内存“细胞”——也就是我们前面展示给大家DRAM基本单元示意图所示的部分,下面我们对这个部分通称为DRAM基本单元。每个DRAM基本单元代表一个“位”——Bit(也就是一个比特),并且有一个由列地址和行地址定义的唯一地址。8个比特组成一个字节,它可代表256种组合(即2的八次幂),字节是内存中最小的可寻址单元。DRAM基本单元不能被单独寻址——否则现在的内存将会更加复杂,而且也没有必要。很多DRAM基本单元连接到同一个列线(Row
line)和同一个行线(Column line),组成了一个矩阵结构,这个矩阵结构就是一个Bank。大部分的SDRAM芯片由4个Bank组成,而SDRAM DIMM (Dual Inline Memory Module双列直插式)可能由8或者16个芯片组成。SDRAM DIMM有14条地址线和64 bit数据线(如果一个DIMM内存使用8bit SDRAM芯片,那么你应该在内存条上看到8个芯片,当然有的DIMM使用4 bit SDRAM芯片,那么你将会在内存条上看到16片)。
以下是对插图的注释:
Row Address Buffer:行地址缓冲
&Column Address Buffer:列地址缓冲
Row DECODER:行解码器
& Column DECODER:列解码器
&Memory Array:内存阵
SENSE AMP:传感放大器
由上图可见一个Bank由内存阵列、sense amp、一个行解码器、一个列解码器组成。如果要理解内存Bank内部工作状况,让我们看看当缓存没有命中后CPU从系统主内存中调用数据的情况。
CPU需要依次读取一个32字节的数据,首先向芯片组发出请求——这通常需要一个时钟周期芯片组将通过14条列地址线发送一个行地址,也就是这个行地址被发送到DIMM所有的芯片上。拥有相同行地址的行被成为一个页面。换句话说,当芯片组向DIMM发送行地址后,就在打开了DIMM上一个页面。
每一个内存bank都有一个传感放大器(sense ampplifier),用来放大从基本单元读出(或者写入)内容时电荷。传感放大器根据从芯片组发送来的行地址读出相应的数据,这个读出过程需要一定的时间这就是RAS到CAS的延迟,简称TRCD。不同质量的SDRAM的TRCD需要2或者3个周期。
现在我们已经有了正确的行地址,不过还不知道确切的到那个基本单元去获得信息。CAS延迟时间就是内存用于取得正确的列地址所需要的时间。CAS延迟时间一般时2或者3个时钟周期。
然后内存基本单元就把信号发送到DIMM的输出缓存,这样芯片组就可以读取它们了。现在我们有了前8个字节的内容,以及在传感放大器中有了正确的行地址,等到下面的24个字节的过程就简单了。这时就由内部计数器负责把下一个列地址的内存基本单元的内容发送到DIMM的输出缓存当中。这样每个时钟周期都有8个字节传送到输出缓存中,这种模式就叫做“突发模式”。
可见,主内存的延迟时间(也就是所谓的潜伏期,从FSB到DRAM)等于下列时间的综合:
FSB同主板芯片组之间的延迟时间(+/- 1个时钟周期)
&  芯片组同DRAM之间的延迟时间(+/- 1个时钟周期)
&RAS到CAS延迟时间:RCD(2-3 个时钟周期,用于决定正确的行地址)
&CAS延迟时间 (2-3 时钟周期,用于决定正确的列地址)
&  另外还需要1个时钟周期来传送数据
  数据从DRAM输出缓存通过芯片组到CPU的延迟时间(+/- 2个时钟周期)
& 可以看出,一个真正的PC100的SDRAM CAS=2)的内存取得最前八个字节的时间是9个时钟周期,而另外24个字节只是需要3个时钟周期,这样PC100的SDRAM取得32个字节的数据只是需要12个时钟周期。
对于同样的情况,也就是当二级缓存未命中的时候,CPU从内存取得数据所需要的延迟时间需要用如下方法计算:CPU倍频×内存延迟时间=CPU延迟时间。如果500MHZ(5×100MHz)的CPU需要5×9个延迟周期。也就是说如果二级缓存没有命中,CPU需要45个时钟中期才能得到新的数据。
&通过以上的介绍,我们已经理解的DRAM工作的基本原理,下面让我们了解一下决定RAM技术速度的因素。
究竟是什么决定DRAM速度?SDRAM是多bank结构,芯片组可以保持一部分曾经访问过的Bank的行地址,也就是说保持一部分已经被打开的“页面”。如果需要访问的数据在同一列中,那么芯片组不需要等待传感器进行变换——这种情况就叫做页面命中。这时RAS到CAS延迟时间就是0个时钟周期,只需要经过CAS延迟就能在内存缓冲调入正确数据。所以,页面命中就意味着我们只需要等待列地址的确立,就能得到需要的数据了。不过有的情况下,芯片组请求的内存页面不是处于打开的状态,这就叫做页面失效。在这种情况下,RAS到CAS延迟时间将是2或者3时钟周期(根据内存的品质不同而不同)。这种情况就是前面我们讨论过的情形。如果芯片组已经保持了某一个Bank的某一个行地址,也就是在某一个bank已经打开了一个页面,而请求的数据是位于同一个bank的不同行地址的数据,这种情况是最糟糕的。这样就意味着传感放大器需要首先回写旧的行地址,然后再转换新的行地址。回写旧的行地址所占用的时间叫做“预转换时间”(Precharge
time),当遇到这种情况时,是最坏的情况。
DEVICE_WIDTH表示设备的带宽(单位为Bit),每个列(COLUMN)表示为DEVICE_WIDTH位(bit),每一行(ROW)有NUM_COLS个COLUMN。每一个BANK包含NUM_ROWS个行,所以一个DEVICE的容量PER_DEVICE_STORAGE=NUM_ROWS*NUM_COLS*DEVICE_WIDTH*NUMBANKS。一个RANK的容量为64bit。所以一个RANK必须有device的个数为NUM_DEVICES_PER_RANK=64/DEVICE_WIDTH。这样我们算在一起,得出一个RANK的大小为PER_RANK_STORAGE=
PER_DEVICE_STORAGE*=NUM_ROWS*NUM_COLS*DEVICE_WIDTH*NUMBANKS* NUM_DEVICES_PER_RANK=NUM_DEVICES_PER_RANK
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:10059次
排名:千里之外
原创:29篇
(1)(4)(5)(5)(1)(13)(1)37480人阅读
计算机原理系列(7)
前面两篇文章介绍了计算机硬件是如何工作的。而从这一章开始将逐渐的转到软件上面来。我们还有内存这一个很重要的部分没有介绍。这一章不仅仅介绍内存的工作原理,还会介绍内存的编址、内存数据存放。逐渐从硬件过渡到软件上来。为后面介绍程序运行打下基础。
1.&内存工作原理
CPU和内存是计算机中最重要的两个组件,前面已经知道了CPU是如何工作的,上一篇也介绍了内存采用的DRAM的存储原理。CPU工作需要知道指令或数据的内存地址,那么这样一个地址是如何和内存这样一个硬件联系起来的呢?现在就看看内存到的是怎么工作的。
1.1 DRAM芯片结构
上图是DRAM芯片一个单元的结构图。一个单元被分为了N个超单元(可以叫做cell),每个单元由M个DRAM单元组成。我们知道一个DRAM单元可以存放1bit数据, 所以描述一个DRAM芯片可以存储N*M位数据。上图就是一个有16个超单元,每个单元8位的存储模块,我们可以称为16*8bit 的DRAM芯片。而超单元(2,1)我们可以通过如矩阵的方式访问,比如 data = DRAM[2.1] 。这样每个超单元都能有唯一的地址,这也是内存地址的基础。
每个超单元的信息通过地址线和数据线传输查找和传输数据。如上图有2根地址线和8根数据线连接到存储控制器(注意这里的存储控制器和前面讲的北桥的内存控制器不是一回事),存储控制器电路一次可以传送M位数据到DRAM芯片或从DRAM传出M位数据。为了读取或写入【i,j】超单元的数据,存储控制器需要通过地址线传入行地址i 和列地址j。这里我们把行地址称为RAS(Row Access Strobe)请求, 列地址称为(Column Access Strobe)请求。
但是我们发现地址线只有2为,也就是寻址空间是0-3。而确定一个超单元至少需要4位地址线,那么是怎么实现的呢?
解决这个问题采用的是分时传送地址码的方法。看上图我们可以发现在DRAM芯片内部有一个行缓冲区,实际上获取一个cell的数据,是传送了2次数据,第一次发送RAS,将一行的数据放入行缓冲区,第二期发送CAS,从行缓冲区中取得数据并通过数据线传出。这些地址线和数据线在芯片上是以管脚(PIN)与控制电路相连的。将DRAM电路设计成二维矩阵而不是一位线性数组是为了降低芯片上的管脚数量。入上图如果使用线性数组,需要4根地址管脚,而采用二维矩阵并使用RAS\CAS两次请求的方式只需要2个地址管脚。但这样的缺点是增加了访问时间。
1.2 内存模块
内存模块也就是我们常说的内存条。我们在购买内存是经常会听到我这个内存采用的是什么颗粒,如下左图,我们看到内存PCB上的一块块的就是内存颗粒。也就是我们DRAM芯片。通过管脚和PCB连接。不同厂商,不同类型的内存可以的大小,管脚,性能,封装都不一样,但是原理都是一样。这里我们就不展开介绍了。而下有图展示了一个1M*4bit的DRAM芯片的管脚图。
对于一个内存颗粒来说,它的容量和字长是有限的,所以我们使用内存是会把多个颗粒组成内存模块来对内存进行字长和容量的扩展。目前的内存一般内存条上面会有多颗内存颗粒,比如一条64M的内存可能是由8个8M*8bit 的SDRAM内存颗粒组成。
1.2.1 字长位数扩展&
位扩展的方法很简单,只需将多片RAM的相应地址端、读/写控制端 和片选信号CS并接在一起,而各片RAM的I/O端并行输出即可。 如上图,我们采用了8个DRAM芯片分,别编号为0-7,每个超单元中存储8位数据。在获取add(row=i,col=j)地址的数据的时候,从每个DRAM芯片的【i, j】单元取出一个字节的数据,这样传送到CPU的一共是8*8b = 64b的数据。我们通过8个8M*8b的内存颗粒扩展为了8M*64b的内存模块。
1.2.2 字存储容量扩展
RAM的字扩展是利用译码器输出控制各片RAM的片选信号CS来实现的。RAM进行字扩展时必须增加地址线,而增加的地址线作为高位地址与译码器的输入相连。同时各片RAM的相应地址端、读/写控制端 、相应I/O端应并接在一起使用。下图是我们通过4个2M*8b的内存颗粒,将内存容量扩展到了8M,字长为8位。
最后,内存通过主板上的内存插槽DIMM和内存总线相连接。对于不同内存比如SDRAM和DDR他们内存金手指的定义是不同的。这里就不需要详细介绍了。
2. 内存编址
前面我们知道了DRAM颗粒以及内存模块是如何扩展字长和容量的。一个内存可能是8位,也可能是64位,容量可能是1M,也可能是1G。那么内存是如何编地的呢?和地址总线,计算机字长之间又有什么关系呢?
计算机在同一时间内处理的一组二进制数称为一个计算机的“字”,而这组二进制数的位数就是“字长”。。通常称处理字长为8位数据的CPU叫8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。 所以这里的字并不是我们理解的双字节(Word)而是和硬件相关的一个概念。一般来说计算机的数据线的位数和字长是相同的。这样从内存获取数据后,只需要一次就能把数据全部传送给CPU。
2.2 地址总线
前面我们已经介绍过地址总线的功能。地址总线的数量决定了他最大的寻址范围。就目前来说一般地址总线先字长相同。比如32位计算机拥有32为数据线和32为地线,最大寻址范围是4G(0x ~ 0xFFFFFFFF)。当然也有例外,Intel的8086是16为字长的CPU,采用了16位数据线和20位数据线。
2.3 内存编址
从前面我们知道一个内存的大小和它芯片扩展方式有关。比如我们内存模块是采用&16M*8bit的内存颗粒,那么我们使用4个颗粒进行位扩展,成为16M*32bit,使用4个颗粒进行字容量扩展变为64M*32bit。那么我们内存模块使用了16个内存颗粒,实际大小是256MB。
我们需要对这个256M的内存进行编址以便CPU能够使用它,通常我们多种编址方式:
按字编址:&&& 对于这个256M内存来说,它的寻址范围是64M,而每个内存地址可以存储32bit数据。按半字编址:对于这个256M内存来说,它的寻址范围是128M,而每个内存地址可以存储16bit数据。按字节编址:对于这个256M内存来说,它的寻址范围是256M,而每个内存地址可以存储8bit数据。
对于我们现在的计算机来说,主要都是采用按字节编址的方式。所以我们可以把内存简单的看成一个线性数组,数组每个元素的大小为8bit,我们称为一个存储单元。这一点很重要,因为后面讨论的所有问题内存都是以按字节编址的方式。 这也是为什么对于32位计算机来说,能使用的最多容量的内存为4GB。如果我们按字编地址,能使用的最大内存容量就是16GB了。
于是很容易想到一个问题,为什么我们要采用字节编址的方式呢?关于这个问题,我在网上基本没有找到答案,甚至都找不到问这个问题的。所以这里没法给出答案,为什么为什么呢? 麻烦知道的朋友告诉我哈。
另一方面的问题是,内存编址方式和DRAM芯片是否有关呢? 我认为还是有一定关系。比如我DRAM的芯片是8M*8bit,那么芯片最小的存储单位就是8bit,那么我们内存编址就不能按照半个字节来编址。否则内存取出8bit,根本不知道你要那4bit传给CPU。也有一种说法是现在的DRAM芯片cell都是8bit,所以采用按字节编址。另一方面应该也和数据总线位宽有关。
3. 内存数据
前面我们知道了,内存是按字节编址,每个地址的存储单元可以存放8bit的数据。我们也知道CPU通过内存地址获取一条指令和数据,而他们存在存储单元中。现在就有一个问题。我们的数据和指令不可能刚好是8bit,如果小于8位,没什么问题,顶多是浪费几位(或许按字节编址是为了节省内存空间考虑)。但是当数据或指令的长度大于8bit呢?因为这种情况是很容易出现的,比如一个16bit的Int数据在内存是如何存储的呢?
3.1 内存数据存放
其实一个简单的办法就是使用多个存储单元来存放数据或指令。比如Int16使用2个内存单元,而Int32使用4个内存单元。当读取数据时,一次读取多个内存单元。于是这里又出现2个问题:
多个存储单元存储的顺序?如何确定要读几个内存单元?
3.1.1 大端和小端存储
Little-Endian 就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
需要说明的是,计算机采用大端还是小端存储是CPU来决定的, 我们常用的X86体系的CPU采用小端,一下ARM体系的CPU也是用小端,但有一些CPU却采用大端比如PowerPC、Sun。判断CPU采用哪种方式很简单:
bool IsBigEndian()
int vlaue = 0x1234;
char lowAdd =
*(char *)&
if( lowAdd == 0x12)
既然不同计算机存储的方式不同,那么在不同计算机之间交互就可能需要进行大小端的转换。这一点我们在Socket编程中可以看到。这里就不介绍了,对以我们单一CPU来说我们可以不需要管这个转换的问题,另外我们目前个人PC都是采用小端方式,所以我们后面默认都是这种方式。
3.1.2 CPU指令
前面我们多次提到了指令的概念,也知道指令是0和1组成的,而汇编代码提高了机器码的可读性。为什么突然在这里介绍CPU指令呢? 主要是解释上面的第二个问题,当我读取一个数据或指令时,我怎么知道需要读取多少个内存单元。
3.1.2.1 CPU指令格式
首先我们来看看CPU指令的格式,我们知道CPU质量主要就是告诉CPU做什么事情,所以一条CPU指令一般包含操作码(OP)和操作
  操作码字段
   地址码字段
根据一条指令中有几个操作数地址,可将该指令称为几操作数指令或几地址指令。
三地址指令: (A1) OP (A2) --& A3
二地址指令:&(A1) OP (A2) --& A1
一地址指令: (AC) OP (A) --& AC   
    零地址指令
A1为被操作数地址,也称源操作数地址; A2为操作数地址,也称终点操作数地址; A3为存放结果的地址。 同样,A1,A2,A3以是内存中的单元地址,也可以是运算器中通用寄存器的地址。所以就有一个寻址的问题。关于指令寻址后面会介绍。
CPU指令设计是十分复杂的,因为在计算机中都是0和1保存,那计算机如何区分一条指令中的操作数和操作码呢?如何保证指令不会重复呢?这个不是我们讨论的重点,有兴趣的可以看看计算机体系结构的书,里面都会有介绍。从上图来看我们知道CPU的指令长度是变长的。所以CPU并不能确定一条指令需要占用几个内存单元,那么CPU又是如何确定一条指令是否读取完了呢?
3.1.2.2 指令的获取
现在的CPU多数采用可变长指令系统。关键是指令的第一字节。&当CPU读指令时,并不是一下把整个指令读近来,而是先读入指令的第一个字节。指令译码器分析这个字节,就知道这是几字节指令。接着顺序读入后面的字节。每读一个字节,程序计数器PC加一。整个指令读入后,PC就指向下一指令(等于为读下一指令做好了准备)。
机器码是00 0000
机器码是16位在内存中占用2个字节:
【】 &- 0x0002
【】 &- 0x0001
比如上面这条MOV汇编指令,把立即数00存入AL寄存器。而CPU获取指令过程如下:
从程序计数器获取当前指令的地址0x0001。存储控制器从0x0001中读出整个字节,发送给CPU。PC+1 = 0X0002.CPU识别出【】表示:操作是MOV AL,并且A2是一个立即数长度为一个字节,所以整个指令的字长为2字节。CPU从地址0x0002取出指令的最后一个字节CPU将立即数00存入AL寄存器。
这里的疑问应该是在第3步,CPU是怎么知道是MOV AL 立即数的操作呢?我们在看下面一个列子。
MOV AL,[0000] 机器码是00 00
这里同样是一条MOV的汇编指令,整个指令需要占用3个字节。
【】 &-0x0003
【】 &- 0x0002
【】 &- 0x0001
我们可以比较一下2条指令第一个字节的区别,发现这里的MOV& AL是,而不是Sample1中的。CPU读取了第一个字节后识别出,操作是MOV AL [D16],表示是一个寄存器间接寻址,A3操作是存放的是一个16位就是地址偏移量(为什么是16位,后面文章会介绍),CPU就判定这条指令长度3个字节。于是从内存0x3读出指令的后2个字节,进行寻址找到真正的数据内存地址,再次通过CPU读入,并完成操作。
从上面我们可以看出一个指令会根据不同的寻址格式,有不同的机器码与之对应。而每个机器码对应的指令的长度都是在CPU设计时就规定好了。8086采用变长指令,指令长度是1-6个字节,后面可以添加8位或16位的偏移量或立即数。&下面的指令格式相比上面2个就更加复杂。
第一个字节的高6位是操作码,W表示传说的数据是字(W=1)还是字节(W=0),D表示数据传输方向D=0数据从寄存器传出,D=1数据传入寄存器。第二个字节中REG表示寄存器号,3位可以表示8种寄存器,根据第一字节的W,可以表示是8位还是16位寄存器。表3-1中列出了8086寄存器编码表第二个字节中的MOD和R/M指定了操作数的寻址方式,表3-2列出了8086的编码
这里没必要也无法更详细介绍CPU指令的,只需要知道,CPU指令中已经定义了指令的长度,不会出现混乱读取内存单元的现象。有兴趣的可以查看引用中的连接。
3.1.3& 内存数据
3.1.3.1 内存数据的操作
从上面我们可以知道,操作数可以是立即数,可以存放在寄存器,也可以存放在内存。对于第一个例子,指令已经说明,操作时是一个字节,于是CPU可以从下一个内存地址读取操作时,而对于第二个列子,操作数只是地址偏移,所以当CPU获得这个数据后,需要转换成实际的内存地址,在进行一次内存访问,把数据读入到寄存器中。这里就出现我们前面提到的问题,这个数据我们要读几个存储单元呢?
MyClass::MyClass (08C1050h)
dword ptr [ebp-4],0
cla.num5 = 500;
dword ptr [ebp-6Ch],1F4h
int b1 = MyClass::num1;
dword ptr [b1],64h
int b2 = MyClass::num2;
dword ptr [b2],0C8h
int b3 = MyClass::num3;
eax,dword ptr ds:[008C9008h]
dword ptr [b3],eax
int b4 = cla.num4;
eax,dword ptr [cla]
dword ptr [b4],eax
int b5 = cla.num5;
eax,dword ptr [ebp-6Ch]
dword ptr [b5],eax
让我们看一段C++代码和对应的汇编代码,操作很简单,创建一个Myclass对象后,对成员变量赋值。而赋值都是试用Mov操作符。对于这些变量我们有赋值操作和取值操作,那么是如何确定要读取或写入数据的大小呢?
cla.num5 = 500;
dword ptr [ebp-6Ch],1F4h
我看先看看赋值操作,往dword ptr [ebp-6Ch]内存存入一个立即数, [ebp-6Ch]是num5的内存地址,而前面的dword ptr 表示这是进行一个双子操作。还记得上面指令格式中第一个字节的W字段吗? 在8086中只能进行字节或字操作,而现在CPU都可以进行双字操作。
int b5 = cla.num5;
eax,dword ptr [ebp-6Ch]
同样,当我们要从一个内存读取数据的时候,也要指定读取数据的操作类型,这里也是双字操作。这样以来,就能从内存中正确的读出需要的长度了。就这么一个简单的赋值操作,获取你从来没想过在内存中怎么存放,又是怎么读取的。这一切都是编译器和CPU在背后为我们完成了。
3.1.3.2 内存对齐
&前面我们清楚了CPU是如何正确读取数大小不同的数据的,最后一部分来看看有关内存对齐的问题。对于大部分程序员来说,内存对齐应该是透明的。内存对齐是编译器的管辖范围。编译器为程序中的每个数据单元安排在适当的位置上。
3.1.3.2.1 对齐原因
从前面我们知道,目前计算机内存按照字节编址,每个地址的内存大小为1个字节。而读取数据的大小和数据线有关。比如数据线为8位那么一次读取一个字节,而如果数据线为32位,那么一次需要读取32个字节,这样是为了一次更多的获取数据提高效率。否则读取一个int变量就需要进行4次内存操作。对于内存访问一般有以下两个条件:
CPU进行一次内存访问读取的数据和字长相同。有些CPU只能对字长倍数的内存地址进行访问。
对于第一个条件一般来说,目前存储器一个cell是8bit,进行位扩展使他和字长还有数据线位数是相同,那么一次就能传送CPU可以处理最多的数据。而前面我们说过目前是按字节编址可能是因为一个cell是8bit,所以一次内存操作读取的数据就是和字长相同。
也正是因为和存储器扩展有关(参考1.2.1的图),每个DRAM位扩展芯片使用相同RAS。如果需要跨行访问,那么需要传递2次RAS。所以以32位CPU为例,CPU只能对0,4,8,16这样的地址进行寻址。而很多32位CPU禁掉了地址线中的低2位A0,A1,这样他们的地址必须是4的倍数,否则会发送错误。
如上图,当计算机数据线为32位时,一次读入4个地址范围的数据。当一个int变量存放在0-3的地址中时,CPU一次就内存操作就可以取得int变量的值。但是如果int变量存放在1-4的地址中呢? 根据上面条件2的解释,这个时候CPU需要进行2次内存访问,第一次读取0-4的数据,并且只保存1-3的内容,第二次访问读取4-7的数据并且只保存4的数据,然后将1-4组合起来。如下图:
所以内存对齐不但可以解决不同CPU的兼容性问题,还能减少内存访问次数,提高效率。当然目前关于这个原因争论很多,可以看看CSDN上的讨论:
3.1.3.2.2 如何对齐内存
内存对齐有一个对齐系数,一般是2,4,8,16字节这样。而不同平台上的对齐方式不同,这个主要是编译器来决定的。
具体的规则可以参考之前转的一篇文章,这里就不详细写了:
通过这一篇对内存工作的介绍,我们从内存的硬件结构,存储方式过渡到了内存的编址方式,然后又探讨了按字节编址带来的问题和解决的办法。这里就涉及到了CPU的指令格式,编译器的支持。最后我们也是从硬件和软件方面讨论了内存对齐的问题。
我自己感觉,内存的访问管理是计算机中最重要的部分,也是计算机硬件和软件之间交互的过渡的一个地方。所以理解了内存的工作原理,对于后面理解不同的内存模型很有帮助。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:294096次
积分:3053
积分:3053
排名:第9176名
原创:50篇
评论:121条
.NET C#开发,Android开发。目前主要从事移动开发,主要负责Android Runtime(ART),欢迎讨论!

我要回帖

更多关于 mt41k128m16jt 107 的文章

 

随机推荐