字符咋存?utf8咋编码?string啥结构?
字符
8个比特组成一个字节。
存字符就是存编号。(字符集)
utf8 go语言默认编码
存汉字怎么破 - 定长编码 - 变长编码
string
s = "test"
s[2] 可以打印,但不能被修改。
要修改的话,可以重新赋值字符串。或者转为slice
字符串变量可以共享底层内容。
Slice
扩容规则。
newCap个元素需多大内存
这里和语言的 内存管理模块 决定。匹配到合适的内存规格。
例如这里 newCap = 5,需要 5*8 = 40byte。
os 给内存会有 8/16/32/48/64/80/96 。。。 这里实际匹配到 48byte。能装6个。
内存对齐
- cpu 要想从 内存 读取数据,要通过地址总线。
- 如果地址总线只有8根,那 256byte 就是最大的寻址空间。
- 每次操作一字节太慢,要想一次操作 4字节就需要 32位数据总线,8字节就需要 64位数据总线.(每次操作的字节数,就是机器字长)
内存示意
内存一般分为这种8块,每次取 相同行列的数据,组合起来就是8byte。(有些cpu支持访问任意地址,那是多做了处理。你要取1-8,它会拿0-7, 8-15,拼接起来两次结果。)
- 为保证程序高效运行,编译器会把各种类型的数据安排到合适的地址,并占用合适的长度。
- 每种类型的对齐值就是它的对齐边界。
要求:存储地址 与 占用的字节数 都要是它对齐边界的倍数。(下图int32要从4开始,不能从2开始)
怎么确定每种类型的对齐边界呢(与平台有关)
32 位机器字长/最大对齐边界:4
64 位机器字长/最大对齐边界:8
减少浪费,提高性能
结构体的对齐边界
确定各成员对齐值,取其中最大的。
要求,每个成员存储地址开头对最大值取余=0,另外 限制类型大小等于其对齐边界的整数倍。
只有每个结构体的大小都是对齐值的整数倍,才能保证数组里每一个都是内存对齐的。
函数调用栈
call、ret指令 栈针布局
定义的函数会被编译为一堆堆机器指令,写入可执行文件。
执行时,可执行文件被加载到内存。机器指令会对应到虚拟地址空间中(代码段)。
一个函数调用另一个函数,编译器会生成一条call指令(将下一条指令的地址入栈,跳转到被调用函数入口处执行,最后有ret指令跳回)。
函数执行时需要有足够的内存空间,存放局部变量、参数等(存放在虚拟空间的栈)
被调用者是通过 栈指针 加上 相应的偏移 来定位到每个参数和返回值的。
函数通过call指令跳转,而每个函数开始时会分配栈帧,结束前又会释放自己的栈帧。ret指令又会把栈恢复到call之前的样子(之前要给返回值赋值,再执行defer函数)
返回值
一般认为返回值通过寄存器传递,但Go