GO--内存管理与分析|青训营笔记

104 阅读5分钟

GO--内存管理与分析|青训营笔记

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

在后面会依次倒叙回顾之前的学习课程,便于复习~

一、课程重点内容

  • 基本概念
  • 垃圾回收机制
  • 内存分配与优化

下面是对课程重点内容的思考与总结,有问题或者错误,可以批评指正呐~

二、基本概念

  • 储备知识

    • 在C语言中,内存管理主要管理的是动态内存动态内存指的是程序在运行时根据需求动态分配的内存,比如 malloc() 函数分配的内存。

    • 内存管理也称为垃圾回收,主要目的是由程序语言的运行时系统管理动态内存,这样做有以下好处:

      • 避免程序员进行内存管理,专注于实现业务逻辑

      • 保证内存使用的正确性和安全性,比如C语言中的内存多次释放:double-free problem, 释放后再次使用use-after-free problem

image.png

三、垃圾回收机制

  • 追踪垃圾回收(Tracing garbage collection)

    • 策略:当一个对象的指针指向关系不可达的时候,该对象就要被回收了。
    • 方法
标记根对象标记包括 静态变量、全局变量、常量、线程栈等
标记:找到可达对象求指针指向关系的传递闭包:从根对象触发,找到所有可达对象
清理:所有不可达对象将存活对象复制到另外的内存空间将死亡对象的内存标记为”可分配“移动并整理存活对象
  • 引用计数(Reference counting)

    • 策略:为每个对象都有一个与之相关联的引用数目,对象存活的条件为当且仅当引用数大于0。

    • 优点:

      • 内存管理的操作被平摊到程序执行过程中
      • 内存管理不需要了解runtime的实现细节,有一些库可以帮助实现引用计数,比如C++智能指针(smart pointer)。
    • 缺点:

      • 维护引用计数的开销较大:通过原子操作保证对引用计数操作的原子性和可见性
      • 无法回收环形数据结构
      • 内存开销:每个对象都引入的额外内存空间存储引用数目

四、内存分配与优化

  • 基本概念:

    • 分配内存

    初始化新进程时,运行时会为进程保留一个连续的地址空间区域。 这个保留的地址空间被称为托管堆。 托管堆维护着一个指针,用它指向将在堆中分配的下一个对象的地址。

    最初,该指针设置为指向托管堆的基址。 托管堆上包含了所有引用类型。 应用程序创建第一个引用类型时,将为托管堆的基址中的类型分配内存。 应用程序创建下一个对象时,垃圾回收器在紧接第一个对象后面的地址空间内为它分配内存。 只要地址空间可用,垃圾回收器就会继续以这种方式为新对象分配空间。

    • 释放内存

    垃圾回收器的优化引擎根据所执行的分配决定执行回收的最佳时间。 垃圾回收器在执行回收时,会释放应用程序不再使用的对象的内存。 它通过检查应用程序的根来确定不再使用的对象。

    每个应用程序都有一组根。 每个根或者引用托管堆中的对象,或者设置为空。 应用程序的根包含线程堆栈上的静态字段、局部变量和参数以及 CPU 寄存器。 垃圾回收器可以访问由实时 (JIT) 编译器和运行时维护的活动根的列表。 垃圾回收器对照此列表检查应用程序的根,并在此过程中创建一个图表,在其中包含所有可从这些根中访问的对象。

  • 分块与缓存

    • 分块

      • Go的内存分配:Go是提前将内存分成一个一个的小块,当创建对象的时候,在内存中找到一个与对象尺寸最接近的一个块分配给他,就完成了一次内存分配。

      • 步骤:调用系统调用mmap()OS申请一大块内存,例如4MB

        先将内存划分大块,例如8KB,称为mspan;再将大块继续划分成特定大小的小块,用于对象分配;noscan mspan:分配不包含指针的对象—GC不需要扫描;scan mspan:分配包括指针的对象—GC需要扫描

    • 缓存

      • Go的内存分配借鉴了TCMalloc(Thread Caching)内存分配器的实现。

      • 步骤:

      • Go在分配内存的时候,都是Goroutine上面执行的代码去分配一块内存,如下图所示,从g出发,找到mp(不懂啥意思??),在p上有一个数据接口mcache,在mcache中存了一组mspans,每个mspans的大小是不一样的。

        mspans里面找到一个最合适的mspan里的一个空余的块,找到这个块之后,返回出去,就完成了一次对象的分配。

        如果mcache里的mspan都是满的,那就就会从下一个级别的缓存,也就是mcentral里面找一个带有空余空间的mspan,并将其填充的mcache里面去,然后再继续分配。

五、课程总结

  • 介绍了自动内存管理的意义
  • 介绍了几种自动内存管理算法
  • 介绍了Go的内存管理方案