详解计算机内存

前言

计算机是进行数据处理的设备,而程序表示的就是处理顺序和数据结构。。由于处理对象数据是存储在内存和磁盘上的,因此程序必须能自由地使用内存和磁盘。本文详解内存的物理结构,逻辑结构以及利用内存构建各种各样数据结构的应用。

一、内存的物理结构

内存实际上是一种名为内存IC的电子元件。内存 IC 中有电源、地址信号、数据信号、控制信号等用于 输入输出的大量引脚(IC的引脚),通过为其指定地址(address),来进行数据的读写。内存 IC 的引脚配置如下图

  • 将电源连接到VCC和GND后, 就可以给其他引脚传递比如0或者1这样的信号。大多数情况下,+ 5V 的直流电压表示1,0V表示0。那么上图内存IC可以存储多少数据呢?一个内存IC能够存储多少数据要看地址信号的个数,因为数据在计算机中存储,每个数据必须对应一个地址,这样这个数据才是有意义的数据。也就是说这个内存IC有多少地址就可以存储多少数据。上面的内存IC有A0~A9 共十个地址信 号引脚,表示可以指定 0000000000~1111111111 共 1024个地址,因此上面的内存IC可以存储1024个数据。
  • 那么一个数据是多大呢?它是由数据信号引脚所确定的,上图内存IC中有D0~D7 共八个数据信号引脚,表示一次可以输入输出8位(= 1字节)的数据。因此,该内存IC一共可以存储1024个1字节的数据。因为1024 = 1K(计算机领域K代表2的10次幂),所以该内存IC的容量就是1KB。
  • 但现在大家使用的计算机至少有512M的内存,也就是512000个1KB大小的内存IC,当然,一台计算机中不太 可能放入如此多的内存IC。通常情况下,计算机使用的内存IC中会有 更多的地址信号引脚,这样就能在一个内存IC中存储数十兆字节的数据。因此,只用数个内存IC,就可以达到512MB的容量。
  • 内存IC写入数据的过程是,首先接通电源(+5V或0V)指定数据,然后地址信号指定存储场所,再把数据的值输入给数据信号存储在指定位置。读取数据时,只需通过A0~A9的地址信号指定数据的存储场所,指定地址中存储的数据就会被输出到 D0~D7 的数据信号引脚 。控制信号是用以控制目前是读操作还是写操作。当写入数据时WD设为1,读取数据时RD设为1。
  • 总体来讲,内存IC内部有大量可以存储8位数据的地方,通过地址指定这些场所, 之后即可进行数据的读写。

二、内存的逻辑模型

  • 虽然内存的实体是内存IC,不过从程序员的角度来看,也可以把 它假想成每层都存储着数据的楼房,并不需要过多地关注内存IC的电 源和控制信号等。如内存为1KB 时,表示的是下图所示的有1024 层的楼房(这里地址的值是从上往下逐渐变大,不过也有与此相反的情况)。
  • 不过,程序员眼里的内存模型中,还包含着物理内存中不存在的概念,那就是数据类型。编程语言中的数据类型表示存储的是何种类型的数据,它从内存来看,就是占用的内存大小(占有的楼层数)的意思。比如C语言中数据类型char代表占用一字节内存大小,short代表占用2字节内存大小,long代表占用4字节内存大小。因此不同的数据类型虽然存放同样的数据,但是他们占用内存的大小是不一样的。
  • 仔细思考一下就会发现,根据程序中所指定的变量的数据类型的 不同,读写的物理内存大小也会随之发生变化,这其实是非常方便的。 大家不妨想一想,假如程序中只能逐个字节地对内存进行读写,那该 多么不便啊。在处理超过1个字节的数据时,还必须要编写分割处理 程序。此外,在不同的编程语言中,变量可以指定的数据类型的最大 长度也不相同。C语言中,8字节(= 64位)的double类型是最大的。

三、理解指针变量

  • 有了上面内存的理解,我想指针就非常容易理解了。因为数据都是存放在计算机相应的地址中,那么,如果有一种变量专门用来存储地址,是不是就可以通过这个地址自由的读写这个地址中的数据了呢?这个变量就是指针变量。指针也是一种变量,它所表示的不是数据的值,而是存储着数据的内存的地址。通过使用指针,就可以对任意指定地址的数据进行读写。如下代码示例了几种数据类型指针的定义:
  • 上面代码中,我们知道d,e,f分别是用来存储内存地址的变量,那么为什么还需要char,short,long这些数据类型呢?实际上,这些数据类型表示的是从指针存储的地址中一次能够读写的数据字节数。比如d一次能够从地址开始位置读取1个字节的数据,而short可以读取2个字节的数据,long可以读取4个字节的数据。

四、数组是高效使用内存的基础

  • 数组是指多个同样数据类型的数据在内存中连续排列的形式。作为数组元素的各个数据会通过连续的编号被区分开来,这个编号称为索引(index)。指定索引后,就可以对该索引所对应地址的内存进行读写操作。而索引和内存地址的变换工作则是由编译器自动实现的。
  • 之所以说数组是内存的使用方法的基础,是因为数组和内存的物理构造是一样的。特别是1字节类型的数组,它和内存的物理构造完全一致。

五、栈、队列以及环形缓冲区

  • 虽然是通过指定索引来使用数组,但这和内存的物理读 写并没有特别大的区别。有没有更人性化的方法来操作计算机的物理内存呢?其中,栈和队列,都可以不通过指定地址和索引来对数组的元素进行读写。那么,栈和队列是如何实现不用指定地址和索引呢?其实很简单,如果我们在内存中预留出栈和队列所需要的空间,并确定好写入和读出的顺序, 就不用再指定地址和索引了。
  • 那么,栈的写入和读出顺序按照“后进先出”的方式(LIFO,Last Input First Out);而相对应队列的写入和读出顺序按照“先进先出”的方式(FIFO,First Input First Out)。同时,如果要在程序中实现栈和队列,就需要以适当的元素数来定义一 个用来存储数据的数组,以及对该数组进行读写的函数对(栈的函数对是Push和Pop;队列的函数对是EnQueue和DeQueue)。总之,这些数据结构都是为了更方便的使用内存。通过使用这些函数,可以很方便的将数据临时保存(写入), 然后再在需要时候把这些数据读出来。
  • 为了充分利用内存空间,队列一般是以环状缓冲区(ring buffer)的方式来实现的。让出队数据的位置可以循环给其它要入队的数据使用。

六、链表使元素的追加和删除更容易

  • 不知道大家有没有发现,队列和栈这种数据结构有一个很大的缺陷,那就是对于数据的读写必须按照顺序进行读写。如果想要在数据中间硬夹一个数据,或者从中间删除一个数据,这都需要耗费极大的动作去移动整个数据结构。那么有没有一种更高效且方便的数据结构可以不用考虑索引的顺序就可以对数组元素进行读写操作呢?这个时候链表就出现了。
  • 在数组的各个元素中,除了数据的值之外,通过为其附带下一 个元素的索引,即可实现链表。数据的值和下一个元素的索引组合在一起,就构成了数组的一个元素。由于链表末尾的元素没有后续的数据,因此就需要用别的 值(在这里是-1)来填充。
  • 在需要追加或删除数据的情况下,使用链表是很高效的。只需要将数据删除或者追加,然后修改上一个元素中的下一个元素索引即可。如果不使用链表数组,那么中途删除或追加元素时,其后的元素就必须要全部移动。

七、二叉查找树使数据搜索更有效

  • 二叉查找树是指在链表的基础上往数组中追加元素时,考虑到数据的大小关系,将其分成左右两个方向的表现形式。例如,假设我们 事先把50这个值保存到了数组中。那么,如果接下来的值比先前保存 的数值大的话,就要将其放到右边,反之如果小的话就放在左边。
  • 那么如何实现二叉查找树呢?其实数组的每个元素 中只要有数据的值和两个索引信息(左右值的索引信息)就可以了。如下图实现上图二叉查找树的逻辑
  • 使用二叉查找树的便利之处在于可以使数据的搜索等更有效率。 在使用一般的数组时,必须从数组的开头按照索引顺序来查找目标数 据。而使用二叉查找树时,当目标数据比现在读出来的数据小时就可 以转到左侧,反之目标数据较大时即可转到链表的右侧,这样就加快 了找到目标数据的速度。

总结

其实上面无论是栈,队列,链表还是二叉查找树他们都是数组的改造,而数据是使用内存的基础,因为数组的结构和内存的物理结构是“一样”的。因此,各种数据结构都是为了更好的使用物理内存,同时根据各种需求对内存的改造而且,而在程序中对内存操作的基础就是数组。

  • 参考:[图灵程序设计丛书].程序是怎样跑起来的

详解计算机内存及基于内存理解的几种数据结构相关推荐

  1. 详解分析MySQL8.0的内存消耗

    文章来源: 学习通http://www.bdgxy.com/ 普学网http://www.boxinghulanban.cn/ 智学网http://www.jaxp.net/ 目录 1.innodb_ ...

  2. 详解计算机内部存储数据的形式 二进制数

    详解计算机内部存储数据的形式-二进制数 前言 要想对程序的运行机制形成一个大致印象,就要了解信息(数据)在计算机内部是以怎样的形式来表现的,又是以怎样的方法进行运算的.在 C 和 Java 等高级语言 ...

  3. Java生产环境下性能监控与调优详解 第2章 基于JDK命令行工具的监控

    Java生产环境下性能监控与调优详解 第2章 基于JDK命令行工具的监控 2-1 JVM的参数类型 标准参数 x参数 XX参数 2-2 查看JVM运行时参数 2-3 jstat查看JVM统计信息 2- ...

  4. NEAT(NeuroEvolution of Augmenting Topologies)算法详解与实践(基于NEAT-Python)

    NEAT(NeuroEvolution of Augmenting Topologies)算法详解与实践(基于NEAT-Python) NEAT算法详解 NEAT算法概述 NEAT编码方案 结构突变 ...

  5. Autosar MCAL-ADC详解(二)-基于Tc27x的cfg软件

    文章目录 前言 AdcHwUnit AdcGroup Channel Emux Select Group Access Mode 配置 结果指针初始化 结果访问 读取buffer中的结果 Group ...

  6. OpenCV-Python实战(14)——人脸检测详解(仅需6行代码学会4种人脸检测方法)

    OpenCV-Python实战(14)--人脸检测详解(仅需6行代码学会4种人脸检测方法) 0. 前言 1. 人脸处理简介 2. 安装人脸处理相关库 2.1 安装 dlib 2.2 安装 face_r ...

  7. 海康服务器装win7系统,详解win7旗舰版系统必须重装的四种情况

    在使用windows7操作系统过程中,难免会遇到一些故障,比如系统中毒或者无法进入系统等这些情况,可是很多人遇到这些问题并不会想到要重装系统,其实重装的方法很简单,而且也是可以彻底解决那些问题的最佳方 ...

  8. python无法使用1号gpu_详解tensorflow2.x版本无法调用gpu的一种解决方法

    最近学校给了一个服务器账号用来训练神经网络使用,服务器本身配置是十路titan V,然后在上面装了tensorflow2.2,对应的python版本是3.6.2,装好之后用tf.test.is_gpu ...

  9. 详解微信小程序页面间传递信息的三种方式

    详解微信小程序页面间传递信息的三种方式 在开发微信小程序的时候,经常会遇到在页面间传递信息的情况,有三种方法可以实现. 1. 使用数据缓存 将要存储的数据使用以下方法放入缓存 wx.setStorag ...

最新文章

  1. android中有关invisible,visible,gone的区别
  2. CentOS防火墙配置方法-详细解读如何配置CentOS防火墙
  3. python中字符串单引号、双引号、三引号_Python:字符串单引号(‘)、双引号(“)、三单引号(”’)和三双引号(“””)的区别...
  4. 谈从10亿个数中找出前10万个最大的
  5. Java进阶知识-数组类型
  6. 直方图尖峰python_Python系统学习 - 绘制直方图
  7. C# 获取对象 大小 Marshal.SizeOf (sizeof 只能在不安全的上下文中使用)
  8. terminal services 找不到_电脑局域网中查看不到其他计算机或无法连接的解决办法...
  9. 案例:监听域对象的属性变更
  10. .net mvc ajax 用html()怎么出来正个页面呀,如何使用jquery或ajax为MVC项目更新c#/ asp.net中的razor部分视图...
  11. 500能不能配个玩英雄联盟的电脑?
  12. 涨跌停计算器_股票涨跌停计算器
  13. 高数复习: 多元函数微分学及其应用
  14. wiringPi (C语言) 控制树莓派引脚
  15. 支付宝-生成二维码实现url,实现支付
  16. 小象学院 nlp 自然语言处理项目实战
  17. BZOJ 1062: [NOI2008]糖果雨(二维树状数组)
  18. Transformer如何用于大规模图像识别?
  19. Redis学习之旅--Redis的数据类型你都知道吗?
  20. 电脑黑屏,只有鼠标光标

热门文章

  1. Apache Beam构建流处理任务
  2. 蕴含命题遇到的疑惑和解答
  3. 用Python删除电脑中的重复文件,竟这么简单
  4. SAP 资产会计过账-总账科目的获取
  5. sql server 2005快捷键
  6. mbedtls 连接 阿里云物联网
  7. 计算机专业笔记本用i5还是i7,笔记本电脑i5和i7的区别大么?
  8. commons-codec使用介绍
  9. theano及cuda环境搭建
  10. GraphQL初探:Java服务示例及Yahoo/Elide