性能优化以及自动内存管理 | 青训营笔记

120 阅读4分钟

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

零、前言

本文记录和整理了本堂课:高性能Go语言发行版优化与落地实践,容易遗忘和比较零碎的知识点,撰写本文的目的一是为了参与青训营笔记活动,二是方便自己未来查缺补漏。

一、本堂课重点内容

  • 优化

    • 内存管理优化
    • 编译器优化
  • 背景

    • 自动管理内存和GO管理内存机制
    • 编译器优化的基本问题和思路

二、详细知识点回顾

2.1 自动内存管理

1. 背景

  • 动态内存

    程序在运行时根据需求产生的内存

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

    由程序语言的运行时系统管理动态内存,可以:

    • 避免手动管理内存,方便程序员专注于业务逻辑
    • 保证内存使用的正确性安全性

2.相关概念

image.png

image.png

pause:暂停mutator业务线程,GC线程做相关GC操作,如内存回收。

Concurrent GC则不会产生pause,而是需要做GC操作时唤醒GC线程,一边运行业务线程一边运行GC线程,所以Concurrent GC必须感知对象指向关系的转变

image.png

评价GC算法的指标

  • 安全性(Safety):不能回收存活的对象 基本要求
  • 吞吐率(Throughput):1 - GC时间/程序执行总时间 花在GC操作上的时间
  • 暂停时间(pause time):stop the world(STW)
  • 内存开销(Space overhead):GC元数据开销

3.追踪垃圾回收

image.png

Copying GC:将存活的对象从一个区复制到另一个区域,随后可以清空原有的区域

image.png

image.png

image.png

4.分代GC(Generational GC)

image.png

5.引用计数

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

  • 对象存活条件:引用计数大于0

  • 优点:

优点1:内存管理操作被平摊到程序执行过程中,因为程序一边在执行,内存操作也顺带被执行了:

来看一下这个例子:开始时p指向o,q为空,o引用计数为1;然后p指向o,q指向o,o引用计数为2;最后p为空o,q为空,o引用计数为0,此时对象o可以被释放。

image.png

image.png

image.png

优点2:内存管理不需要了解runtime实现的细节,而只需要维护对象的引用计数,便完成了内存管理:比如C++的智能指针

  • 缺点:

缺点1:维护引用计数开销大

缺点2:无法回收环形数据结构

image.png

缺点3:额外内存开销:每个对象都需要引入额外内存存储其引用数目

缺点4:回收大数据结构的内存时依然可能引发暂停

2.2 Go内存分配

1. 内存分配--分块

为对象在heap上分配内存:

image.png

缓存:

image.png

2. GO内存管理优化

  • 为什么要进行内存优化
    • 对象分配时非常高频的操作:每秒分配几GB的内存
    • 小对象占比高
    • Go分配内存比较耗时

image.png

  • 优化防范Balanced GC

image.png

GAB对于Go内存管理来说是一个大对象

本质:将多个小对象的分配合并成一次大对象分配

问题:GAB的对象分配会导致内存被延迟释放,一个小对象的存活会使该GAB的存活

解决方案:

image.png

2.3 编译器和静态分析

编译器结构

image.png

静态分析

静态分析:不执行程序代码,推到程序的行为,分析程序的性质

控制流:(Control flow)程序控制的流程

数据流:(Data flow)数据在控制流上的传递

image.png

通过控制流和数据流,我们可以知道更多关于程序的性质:

image.png

过程内分析和过程间分析

  • 过程内分析(Intra-procedural analysis)

    • 仅在函数内部进行分析
  • 过程间分析(Inter-procedural analysis)

    • 考虑函数调用时参数传递和返回值的数据流和控制流
  • 为什么过程间分析是个问题

    • 需要数据流分析得知i的具体类型,才能知道i.foo()调用的是哪个foo()
    • 根据i的具体类型,产生新的控制流,i.foo(),继续分析
    • 过程间分析需要同时考虑控制流和数据流--联合求解,比较麻烦

image.png

2.4 Go编译器优化

image.png

1. 函数内联

内联:将被调用函数的函数体的副本替换到被调用函数的位置,同时重写代码以反映参数的绑定

  • 优点
    • 消除函数调用开销
    • 将过程间分析转换为过程内分析

image.png

image.png

2. Beast Mode

Beast Mode:

image.png

逃逸分析:

image.png

2.5 总结

image.png