Go语言上手(五)-性能优化与自动内存管理 | 青训营笔记

98 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 5 天

本节内容:

性能优化与自动内存管理
Go的内存管理&编译器

性能优化是什么?

提升软件系统处理能力,减少不必要的消耗,充分发掘计算机算力。

为什么要做性能优化?

用户体验:

带来用户体验的提升——让刷抖音更丝滑,让双十一购物不再卡顿 资源高效利用:

降低成本,提高效率——很小的优化乘以海量机器会是显著的性能提升和成本节约

自动内存管理

动态内存

自动分配 maclloc()

自动内存管理(垃圾回收)

避免手动内存管理

保证内存使用的正确性和安全性

三个任务
  • 为新对象分配空间
  • 找到存活对象
  • 回收死亡对象的内存空间
相关概念(涉及到语言底层)

image-20230119101120618

评价GC算法
  • 安全性 不能回收存活的对象 基本要求
  • 吞吐率 1-(GC时间)/(程序执行总时间)
  • 暂停时间 业务是否感知
  • 内存开销 GC元数据开销
追踪垃圾回收

对象被回收的条件:指针指向关系不可达的对象

标记根对象:静态变量,全局变量,常量,线程栈登

标记:找到可达对象

求指针指向关系的传递闭包:

清理:所有不可达对象

将存活对象复制到另外的内存空间(copying gc)

将死亡对象的内存标记为“可分配”(Mark——sweep Gc)

移动并整理存活对象(mark-compact gc)

分代gc

每个对象都有年龄:经历过gc的次数

年轻代

常规的对象分配

存活对象很少,采用copying collection

老年代

对象一直活着,反复复制开销大

采用mark-sweep collection

引用计数

每个对象都有与之关联的引用数目

对象存活的条件:当且仅当引用数大于0

优点

可以一边执行一边操作

缺点

维护引用计数的开销较大;通过原子操作保证对引用计数操作的原子性和可见性

不能回收环形的结构

Go的内存管理&编译器

分块

目标:为对象在heap上分配内存

提前将内存分块

image-20230119103533987

先分大块,然后再分小块

缓存

image-20230119103729458

对象分配是非常高频的操作:每秒分配GB级别的内存

小对象占比高

Go的内存分配比较耗时

编译器结构

image-20230119105031203

静态分析

不去执行代码,推导此程序的行为,分析程序的性质

控制流:程序执行的流程

数据流:程序执行的流程

int a=30
int b=9-(a/5)
int c
c=b*4
if (c > 10){
c=c-10
}
return c*(60/a)

过程内分析和过程间分析

过程内分析下

仅在函数内部进行分析

过程间分析下

考虑过程调用的参数传递和返回值的数据流和控制流

函数内联

image-20230119110716238

逃逸分析

image-20230119111115620

课程总结

性能优化

  • 自动内存管理
  • GO的内存管理
  • 编译器与静态分析
  • 编译器优化

实践

  • balanced gc 优化对象分配
  • beast mode 提高代码性能

课程收获

这两节课非常的硬核,接触到了底层的东西,非常的有深度,网上的资料也很少,非常的nice