十六.数字解析
Go语言中有丰富的数据类型,除了基本的整型、浮点型、布尔型、字符串外,还有数组、切片、结构体、函数、map、通等。
Go语言的基本类型和其他语言大同小异。但是go有一个新类型是rune
主要的区别
byte和rune类型
组成每个字符串的元素叫做字符,可以通过遍历或者单个获取字符串元素或字符。字符是用单引号包裹起来的。
在Go里字符与字符串是通过是双引号或单引号来进行严格区分的。
Go语言的字符有以下两种:
- uint8类型,或者叫byte型,代表了ASCII码的一个字符。
- rune类型,代表一个UTF-8字符
当需要处理中文\日文或者其它复合字符的时候,则要用到rune类型。rune类型实际是一个int32。
类型转换
只要整型和浮点型能够相互转换
**go 不支持隐式转换类型 **
举例
package main
import "fmt"
func main() {
var sum int = 17
var count int = 5
var mean float32
mean = float32(sum) / float32(count)
fmt.Printf("mean 的值为: %f\n", mean)
}
十七.进程信息
1 概念
进程是一个正在执行的程序,是操作系统中最小的资源分配单位。
2 结构
当一个程序被加载到内存中并成为一个进程时,它可以分为四个部分:堆栈、堆、文本和数据。
- 堆栈
进程堆栈包含临时数据,例如方法/函数参数、返回地址和局部变量。
- 堆
这是在进程运行时动态分配给进程的内存。
- 数据
包含全局变量和静态变量。
- 文本
包括由程序计数器的值和处理器寄存器的内容表示的当前活动。
3 进程上下文切换
进程的上下文切换是指 cpu 从一个进程切换到另一个进程。
进程上下文切换主要包含两个主要过程:进程地址空间切换和处理器状态切换
1.进程地址空间切换
-
切换原因:进程地址空间指的是进程所拥有的虚拟地址空间,而这个地址空间是假的,是 linux 内核通过数据结构来描述出来的,从而使得每一个进程都感觉到自己拥有整个内存的假象,cpu 访问的指令和数据最终会落实到实际的物理地址,对用进程而言通过缺页异常来分配和建立页表映射。进程地址空间内有进程运行的指令和数据,因此到调度器从其他进程重新切换到我的时候,为了保证当前进程访问的虚拟地址是自己的必须切换地址空间。
-
切换方式:将当前进程的 pgd 虚拟地址转换为物理地址存放在用户控件的页表基址寄存器,当访问用户空间地址的时候 mmu 会通过这个寄存器做遍历页表,获得物理地址。
-
原理是进程想要访问一个用户空间虚拟地址,cpu 的 mmu 所做的工作,就是从页表基址寄存器拿到页全局目录的物理基地址,然后和虚拟地址配合来查查找页表,最终找到物理地址进行访问(当然如果 tlb 命中就不需要遍历页表),每次用户虚拟地址访问的时候(内核空间共享不考虑),由于页表基地址寄存器内存放的是当前执行进程的页全局目录的物理地址,所以访问自己的一套页表,拿到的是属于自己的物理地址(实际上,进程是访问虚拟地址空间的指令数据的时候不断发生缺页异常,然后缺页异常处理程序为进程分配实际的物理页,然后将页帧号和页表属性填入自己的页表条目中),就不会访问其他进程的指令和数据,这也是为何多个进程可以访问相同的虚拟地址而不会出现差错的原因。
地址空间切换过程中,还会清空 tlb(页表缓存:用于存放虚拟地址映射至物理地址的标签页表条目),防止当前进程虚拟地址转化过程中命中上一个进程的 tlb 表项,一般会将所有的 tlb 无效,但是这会导致很大的性能损失,因为新进程被切换进来的时候面对的是全新的空的 tlb,造成很大概率的 tlb miss,需要重新遍历多级页表
2.处理器状态切换
-
切换原因:需要将进程的内核栈和执行流进行切换。
-
切换方式:处理器状态切换就是将前一个进程的 sp,pc 等寄存器的值保存到一块内存上,然后将即将执行的进程的 sp,pc 等寄存器的值从另一块内存中恢复到相应寄存器中,恢复 sp 完成了进程内核栈的切换,恢复 pc 完成了指令执行流的切换。
sp 寄存器在任意时刻会保存我们栈顶的地址.
pc 寄存器也称为程序寄存器,用于存储指向下一条指令的地址,也即将将要执行的指令代码。