b : bit , B : Byte , 8 bit = 1 Byte
M 是数量单位 1024 = 1K , 1024K = 1M, 1024M = 1G
b(bit) 是一个二进制位,8bit = 1B, 1024B = 1KB(容量),
带宽给的是数量单位,比如 100M的带宽(容量单位),换算成容量,100 / 8 = 12.5 MB/s,(因为传输的是二进制数据)
寻址能力,2^20 = 1M 是数量单位,由于地址总线指向的是内存条,与内存条的内存地址相链接,这时数量单位和容量单位是一致的,当寻址能力是1M,容量单位也是1M
因为内存条的最小单位是字节 (8bit = 1B),这时数量和容量能过一一对应,所以当寻址能力为1M时,内存中能够寻找的容量为 1MB
进制
学习进制的障碍
很多人学不好进制,原因是总以十进制为依托去考虑其他进制,需要运算的时候也总是先转换成十进制,这种学习方法是错误的.
我们为什么一定要转换十进制呢?仅仅是因为我们对十进制最熟悉,所以才转换.
每一种进制都是完美的,想学好进制首先要忘掉十进制,也要忘掉进制间的转换!
进制的定义
八进制由8个符号组成:0 1 2 3 4 5 6 7 逢八进一
十进制由10个符号组成:0 1 2 3 4 5 6 7 8 9逢十进一
N进制就是由N个符号组成:逢N进一
计算机中常见的数据宽度
位(Bit): 1个位就是1个二进制位.0或者1
字节(Byte): 1个字节由8个Bit组成(8位).内存中的最小单元Byte.
字(Word): 1个字由2个字节组成(16位),这2个字节分别称为高字节和低字节.
双字(Doubleword): 1个双字由两个字组成(32位)
general purpose register 寄存器 ,cpsr 标记寄存器
数据在计算机中是有宽度的
当在ffffffff前面加个值后,数据会丢失,所以数据是有宽度的
16进制 0xffffffff,是4个字节的1,(1111 1111 1111 1111 1111 1111 1111 1111)一个字节是8个bit
CPU&寄存器
如果寄存器以x开头则表明的是一个64位的寄存器,代表着有64根总线,数据吞吐量为64 / 8 = 8 个字节。
如果以w开头则表明是一个32位的寄存器,在系统中没有提供16位和8位的寄存器供访问和使用。其中32位的寄存器是64位寄存器的低32位部分并不是独立存在的。
对程序员来说,CPU中最主要部件是寄存器,可以通过改变寄存器的内容来实现对CPU的控制, 不同的CPU,寄存器的个数、结构是不相同的
浮点和向量寄存器
因为浮点数的存储以及其运算的特殊性,CPU中专门提供浮点数寄存器来处理浮点数
浮点寄存器 64位: D0 - D31 32位: S0 - S31
现在的CPU支持向量运算.(向量运算在图形处理相关的领域用得非常的多)为了支持向量计算系统了也提供了众多的向量寄存器.
向量寄存器 128位:V0-V31, 位数最高的寄存器
通用寄存器
通用寄存器也称数据地址寄存器通常用来做数据计算的临时存储、做累加、计数、地址保存等功能。定义这些寄存器的作用主要是用于在CPU指令中保存操作数,在CPU中当做一些常规变量来使用。
ARM64拥有有32个64位的通用寄存器 x0 到 x30,以及XZR(零寄存器),这些通用寄存器有时也有特定用途。
那么w0 到 w28 这些是32位的. 因为64位CPU可以兼容32位.所以可以只使用64位寄存器的低32位.
比如 w0 就是 x0的低32位!
pc寄存器(program counter)
为指令指针寄存器,它指示了CPU当前要读取指令的地址
在内存或者磁盘上,指令和数据没有任何区别,都是二进制信息
CPU在工作的时候把有的信息看做指令,有的信息看做数据,为同样的信息赋予了不同的意义
比如 1110 0000 0000 0011 0000 1000 1010 1010
可以当做数据 0xE003008AA
也可以当做指令 mov x0, x8
CPU根据什么将内存中的信息看做指令?
CPU将pc指向的内存单元的内容看做指令
如果内存中的某段内容曾被CPU执行过,那么它所在的内存单元必然被pc指向过
高速缓存
iPhoneX上搭载的ARM处理器A11它的1级缓存的容量是64KB,2级缓存的容量8M.
CPU每执行一条指令前都需要从内存中将指令读取到CPU内并执行。而寄存器的运行速度相比内存读写要快很多,为了性能,CPU还集成了一个高速缓存存储区域.当程序在运行时,先将要执行的指令代码以及数据复制到高速缓存中去(由操作系统完成).CPU直接从高速缓存依次读取指令来执行.
bl指令
CPU从何处执行指令是由pc中的内容决定的,我们可以通过改变pc的内容来控制CPU执行目标指令
ARM64提供了一个mov指令(传送指令),可以用来修改大部分寄存器的值,比如
mov x0,#10、mov x1,#20
但是,mov指令不能用于设置pc的值,ARM64没有提供这样的功能
ARM64提供了另外的指令来修改PC的值,这些指令统称为转移指令,最简单的是bl指令
例
bl :正在调用方法或函数
栈
SP和FP寄存器
sp寄存器在任意时刻会保存我们栈顶的地址.
fp寄存器也称为x29寄存器属于通用寄存器,但是在某些时刻我们利用它保存栈底的地址!
注意:ARM64开始,取消32位的 LDM,STM,PUSH,POP指令! 取而代之的是ldr\ldp str\stp
ARM64里面 对栈的操作是16字节对齐的!!
关于内存读写指令
注意:读/写 数据是都是往高地址读/写
str(store register)指令
将数据从寄存器中读出来,存到内存中.
ldr(load register)指令
将数据从内存中读出来,存到寄存器中
此ldr 和 str 的变种ldp 和 stp 还可以操作2个寄存器.
注: ios 中拉伸栈空间是由高地址到低地址。由低地址到高地址是堆空间。当堆和栈空间想加大于内存空间,就会发生堆栈溢出的问题。 (线程保护,进程保护,每一个独立的进程都有自己独立的内存空间)
内存泄漏是在堆空间中,一个对象或者一个结构体在堆中要先做free,然后free指针置为nil,会产生坏地址指针(野指针)
栈空间是高地址向低地址拉伸的,但是也是先进后出的,那么上面的栈数据怎么释放呢?
栈是为函数开辟的,函数调用栈,栈拉伸,所以不存在提前释放。
死循环和死递归有什么区别?
死循环不一定会崩溃,死递归会崩溃,int a(){ a(); } 内存 stack overflow ,堆栈溢出
//每一次指令只有4个字节
给程序员操作的寄存器只有x0 ~ x30,
str w0, [sp,#0xc]
这句话会出问题,因为A中将栈的空间拉伸了32个字节,执行完A后回到mian函数,这时sp指针拿着原来的偏移去找原来函数,会找不到,就会出现坏地址访问,所以A操作完后要进行 恢复栈的平衡,就是把栈内存释放掉
add sp, sp,#0x20