本文是《go调度器源代码情景分析》系列 第一章 预备知识的第2小节。


内存是计算机系统的存储设备,其主要作用是协助CPU在执行程序时存储数据和指令。

内存由大量内存单元组成,内存单元大小为1个字节(1字节包含8个二进制位), 每个内存单元都有一个编号,更专业的说法是每一个内存单元都有一个地址,我们在编写汇编代码或编译器把用高级语言所写的程序编译成汇编指令时,如果要读写内存,就必须在指令中指定内存地址,这样CPU才知道它要存取哪个或哪些内存单元。

大家都知道,高级语言中有变量的概念,变量又有全局变量和函数局部变量之分,而不管是哪种变量(除了C语言中申明为register的变量),都需要保存在内存之中, 同时,绝大多数类型的变量都不会只占一个字节大小的内存,但是每个内存单元却只有一个字节大小,那么像这种大于一个字节的变量是如何保存在内存中的呢?聪明的你一定会想到,任何大于一个字节的变量都存储在相邻的几个内存单元中,事实也确实如此,比如go语言中的int64类型的变量在内存中就被存放在连续的8个内存单元之中,要读写该变量,只需在汇编指令中指定这些内存单元的起始地址以及读写的字节数即可。说到这里,问题又来了,既然一个int64类型的变量在内存中占8个字节,那么如何安排这8个字节来存储64位的整型数据呢?比如如何在内存中存储0x1122334455667788这个16进制表示的整型值,是把高位的0x11放在这8个内存单元中的第一个字节还是把低位的0x88放在第一个字节呢?其实两种方案都是可以的,不同的CPU采用的方案也可能不同,比如X86系列(包括AMD64)的CPU就会把低位的0x88放在起始位置,而PowerPC CPU则会把高位的0x11放在起始的第一个字节,这就是所谓的大小端存储模式:

  • 大端存储模式:数据的高字节保存在内存的低地址中,低字节保存在内存的高地址中。
  • 小端存储模式:数据的高字节保存在内存的高地址中,低字节保存在内存的低地址中。

需要注意的是大小端存储模式与CPU相关,而与内存无关,内存只管保存数据而不关心数据是什么以及怎么解释这些数据。下图是大小端存储模式的示意图:

下面再用上一节讨论寄存器时使用过的例子来帮助我们加深对内存的理解:

c = a + b // go语言代码
mov (%rsp),%rdx     #把变量a的值从内存中读取到寄存器rdx中
mov 0x8(%rsp),%rax #把变量b的值从内存中读取到寄存器rax中
add %rdx,%rax #把寄存器rdx和rax中的值相加,并把结果放回rax寄存器中
mov %rax,0x10(%rsp) #把寄存器rax中的值写回变量c所在的内存

这里的4条指令有3条跟内存读写有关,指令中的rsp寄存器里面存放的是一个内存地址,现假设这个内存地址是X, 则第一条指令 mov (%rsp),%rdx 表示把从地址为X开始的8个内存单元中的值读取到rdx寄存器中(因为rdx是一个64位寄存器,这就隐含了要一次读取连续的8个字节,指令中的地址只是起始地址,这个地址开始的8个字节是变量a所在的位置),第二条指令类似,只是起始地址为X + 0x8(变量b在内存中的地址),最后一条指令表示把rax寄存器中的值写入从地址为X + 0x10开始的8个内存单元中。下图直观的表示了上面4条指令的执行过程。

对这个图做个简单的说明:

  1. 这里假定rsp寄存器的值是X
  2. 图中的内存部分,每一行有8个内存单元,它们的地址从右向左依次加一,即如果最右边的内存单元的地址为X的话,则同一行最左边的内存单元的地址为X+7。
  3. 灰色箭头表述数据流动方向
  4. 紫红色数字n表示上述代码片段中的第n条指令

最后,我们对内存部分做个简单的总结:

  • 内存中的每个字节都有一个地址;
  • 任何大于一个字节的变量在内存中都存储在相邻连续的的几个内存单元之中;
  • 大端存储模式指数据的高字节保存在内存的低地址中,低字节保存在内存的高地址中;小端存储模式指数据的高字节保存在内存的高地址中,低字节保存在内存的低地址中。

go语言调度器源代码情景分析之三:内存的更多相关文章

  1. go语言调度器源代码情景分析之五:汇编指令

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第4小节. 汇编语言是每位后端程序员都应该掌握的一门语言,因为学会了汇编语言,不管是对我们调试程序还是研究与理解计算机底层的一些运 ...

  2. go语言调度器源代码情景分析之四:函数调用栈

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第3小节. 什么是栈 栈是一种“后进先出”的数据结构,它相当于一个容器,当需要往容器里面添加元素时只能放在最上面的一个元素之上,需 ...

  3. go语言调度器源代码情景分析之二:CPU寄存器

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第1小节. 寄存器是CPU内部的存储单元,用于存放从内存读取而来的数据(包括指令)和CPU运算的中间结果,之所以要使用寄存器来临时 ...

  4. go语言调度器源代码情景分析之一:开篇语

    专题简介 本专题以精心设计的情景为线索,结合go语言最新1.12版源代码深入细致的分析了goroutine调度器实现原理. 适宜读者 go语言开发人员 对线程调度器工作原理感兴趣的工程师 对计算机底层 ...

  5. go语言调度器源代码情景分析之六:go汇编语言

    go语言runtime(包括调度器)源代码中有部分代码是用汇编语言编写的,不过这些汇编代码并非针对特定体系结构的汇编代码,而是go语言引入的一种伪汇编,它同样也需要经过汇编器转换成机器指令才能被CPU ...

  6. linux 内核源代码情景分析——linux 内存管理的基本框架

    386 CPU中的页式存管的基本思路是:通过页面目录和页面表分两个层次实现从线性地址到物理地址的映射.这种映射模式在大多数情况下可以节省页面表所占用的空间.因为大多数进程不会用到整个虚存空间,在虚存空 ...

  7. 《Android系统源代码情景分析》连载回忆录:灵感之源

    上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个 ...

  8. linux调度器源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 上期文章linux调度器源码分析 - 概述(一)已经把调度器相关的数据结构介绍了一遍,本篇着重通过代码说明 ...

  9. [翻译] 深入浅出Go语言调度器:第一部分 - 系统调度器

    目录 译者序 序 介绍 系统调度器 执行指令 Figure 1 Listing 1 Listing 2 Listing 3 线程状态 任务侧重 上下文切换 少即是多 寻找平衡 缓存行 Figure 2 ...

随机推荐

  1. Java虚拟机-垃圾收集器

    垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的 ...

  2. “蝉原则”与CSS3随机多背景随机圆角等效果

    一.什么是“蝉原则”? “蝉原则”,英文称作“cicada principle”,是一种让事物的重复出现符合“自然随机性”的规则,为什么这么说呢? “蝉原则”源自于北美,中国似乎并未有这样的说法,这背 ...

  3. Java容器:Set

    Set和数学中的集合十分类似,在Java中,Set是一种绝不会包含两个相等元素的存储结构.在阅读此文前请阅读Java容器:Map. Set方法 增添方法: boolean add(E e); bool ...

  4. java 字符串池【转】

    java 字符串池 java运行环境有一个字符串池.比如String str="abc"时,会首先查看字符串池中是否存在字符串"abc",如果存在则直接将&qu ...

  5. 关于ajax原理阐述

    ajax是什么呢?说白了就是一个请求,一个读取服务器资源以及提交资源到服务器的中间处理机制,那它具体是怎样工作的,又有怎样的原理呢?var ajax=function(url,fnSucceed,fn ...

  6. [ SSH框架 ] Struts2框架学习之四(自定义拦截器)

    一.Struts2的拦截器 1.1 拦截器概述 拦截器,在AOP( Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作.拦截 ...

  7. spring事务机制

    一.Java动态代理 1.定义 Java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理. 默认情况下会采用JDK的动态代理实现AOP . 2. ...

  8. 第九章——运行tensorflow(Up and Running with TensorFlow)

    本章简单介绍了TensorFlow的安装以及使用.一些细节需要在后续的应用中慢慢把握. TensorFlow并不仅仅局限于神经网络和机器学习,它甚至可以用于量子物理仿真. TensorFlow的优势: ...

  9. 手动撸个Android雷达图(蜘蛛网图)RadarView

    公司产品需要一个雷达图来展示各维度的比重,网上找了一波,学到不少,直接自己上手来撸一记 无图言虚空 简单分析一波,确定雷达图正几边形的--正五边形 int count=5,分为几个层数--4 层 in ...

  10. Python定时任务

    在项目中,我们可能遇到有定时任务的需求.其一:定时执行任务.例如每天早上 8 点定时推送早报.其二:每隔一个时间段就执行任务.比如:每隔一个小时提醒自己起来走动走动,避免长时间坐着.今天,我跟大家分享 ...