这是我参与「第五届青训营 」笔记创作活动的第3天。
引言
今天的课程是关于Go语言性能优化的,主要从内存优化和编译器优化两个方面进行切入。这篇文章主要是针对今天课程的记录和总结。
一、本堂课重点内容
本堂课的知识点
- 自动内存管理
- Go的内存管理和优化
- 编译器和静态分析
- Go编译器优化
二、详细知识点介绍
- 自动内存管理
-
自动内存管理即由程序语言的运行时系统管理动态内存,避免手动内存管理,专注于实现业务逻辑
-
自动内存管理也要保证内存使用的正确性和安全性: double-free problem, use-after-free problem
内存管理主要三个任务
- 为新对象(刚创建)分配内存空间
- 找到存活对象(即后续过程还需要利用到的对象)
- 回收死亡对象(后续过程无需使用的对象)的内存空间
相关类型线程来完成上述任务
- Mutator: 业务线程,分配新对象,修改对象指向关系
- Collector:GC 线程,找到存活对象,回收死亡对象的内存空间
GC线程算法
- Serial GC: 只有一个 collector
- Parallel GC: 并行 GC,支持多个 collectors 同时回收的 GC 算法
- Concurrent GC: 并发 GC,支持 mutator(s) 和 collector(s) 同时执行的 GC 算法
- Go的内存管理和优化
内存管理的例子:
for i:=0; i<10 ;i++{
x := i*i
y := x/2
fmt.Println(x,y)
}
每次循环的开始都会创建临时变量i,然后每次循环迭代中创建临时变量x,y
Go语言的自动垃圾收集器是如何知道一个变量是何时可以被回收的呢?
基本的实现思路是:从每个包级的变量和每个当前运行函数的每一个局部变量开始,通过指针或引用的访问路径遍历,是否可以找到该变量。如果不存在这样的访问路径,那么说明该变量是不可达的,也就是说它是否存在并不会影响程序后续的计算结果。
Go编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,并且这个选择并不是由用var还是new声明变量的方式决定的。
- 编译器
编译就是将高级语言程序转换成汇编语言程序/或其他语言程序的过程。
Java的编译器就是将Java程序源代码编译成字节码(class文件)
编译过程
- 词法分析
词法分析的任务是从左往右逐行扫描源程序的字符,识别出各个单词,确定单词的类型(词素) 。将识别出的单词转换成统一的机内表示———词法单元(token)形式
〈token-name, attribute-value〉 <种别码, 属性值>
如关键字(if、else、for等)一词一码
标识符(变量名,函数名等)多词一码
- 语法分析
语法分析器从词法分析器输出的token序列中识别出各类短语,并构造语法分析树
- 语义分析
语义分析器(semantic analyzer)使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。它同时也收集类型信息,并把这些信息存放在语法树或符号表中,以便在随后的中间代码生成过程中使用。
语义分析的一个重要部分是语义检查
- 变量或函数未经过声明就使用
- 变量或函数名重复声明
- 运算分量的类型不匹配(比如数组的名字和函数的名字进行相加,当然也可能存在类型转换)
- 操作符与操作数之间的类型不匹配(数组的下标不是整数、函数调用的参数类型或数目不匹配)
- 编译器优化
三、实践练习例子
待补充
四、课后个人总结
今天这堂课程明白了为何要进行性能优化,即提升软件系统处理能力,减少不必要的消耗,充分发掘计算机算力,学习到了从内存管理的角度和编译器的角度对系统进行优化,这两个方面其实就是包含在SDK中,这样就能对大多数场景进行优化。
五、引用参考
主要参考了青训营课程资料和Go语言中文网中的相关资料