当前位置: 首页 > news >正文

深入浅出 Golang 内存管理

了解内存管理~

前言:

本节课主要介绍了内存管理知识与自动内存管理机制,并对目前 Go 内存管理过程中存在的问题提出了解决方案,同时结合了上次课程学习的《Go 语言性能优化》相关知识,提供可行性的优化建议 …

image.png


自动内存管理

Go 语言作为相对新型的语言,自动内存管理肯定是少不了的了,和 Java 一样,Go 语言也有垃圾回收机制,可以实现自动内存管理,下面让我们来了解一些自动内存管理的相关知识。

🎈自动内存管理的概念:

程序运行时的内存分配策略有很多种:单一连续分配、固定分区分配、动态分区分配,现代的程序一般采用动态分区分配,会根据程序在运行时的需求动态地分配内存(malloc()),将动态分配地内存称作动态内存

image.png

自动内存管理是指由程序语言地运行时系统管理动态内存。

  • 避免手动内存管理,专注于实现业务逻辑;
  • 保证内存使用的正确性和安全性。

自动内存管理也可以叫垃圾回收(GC),主要负责:

  • 为新对象分配空间;
  • 找到存活对象;
  • 回收死亡对象的内存空间。
GC 相关概念
  • Mutator:业务线程,分配新对象,修改对象指向关系;
  • Collector:GC 线程,找到存活对象,回收死亡对象的内存空间;
  • Serial GC:只有一个 Collector 的 GC 算法;
  • Parallel GC:支持多个 Collectors 同时回收的 GC 算法;
  • Concurrent GC:Mutator(s) 和 Collector(s) 可以同时执行的 GC 算法。

image.png

🎯评价 GC 算法的几大指标:

  • 安全性:不能回收存活的对象;
  • 吞吐率:用来衡量 GC 时间的占比,其值为 1 - GC 时间 / 程序执行总时
  • 暂停时间:GC 可能会导致暂停业务,一般希望暂停时间越短越好;
  • 内存开销:GC 元数据开销。

在学习 Go 内存管理之前,我们先来了解一下垃圾回收的几种实现方案~

追踪垃圾回收

追踪垃圾回收是 GC 策略的其中一种,属于间接式的回收策略,这种策略不会直接寻找垃圾本身,而是先去找到存活的对象,然后反过来判断其余的对象应该被回收掉。

image.png

✔追踪垃圾回收的步骤:

  1. 标记根对象:静态变量、全局变量、常量、线程栈等;
  2. 标记:从根对象出发,找到所有可达对象;
  3. 清理:回收掉所有不可达对象。
    • 将存活对象复制到另外的内存空间(Copying GC)
    • 将死亡对象的内存标记为“可分配”(Mark-sweep GC)
    • 移动并整理存活对象(Mark-compact GC)

(根据对象的生命周期,会使用不同的标记和清理策略)

分代 GC(Generational GC)

分代 GC 是基于分代假说的内存管理策略,是一种比较常见的策略。

弱分代假说认为绝大多数对象都是朝生夕灭的,生命很短;强分代假说认为活得越久也就是熬过越多次垃圾收集过程的对象就越难以消亡,这两个分代假说共同奠定了垃圾回收的设计原则。

image.png

分代 GC 策略会给每个对象一个年龄(经历过 GC 的次数),将对象分成老年代和年轻代,把不同年龄的对象放在堆内存(Heap)的不同区域,为其制定不同的 GC 策略,从而降低整体内存管理的开销。

  • 年轻代(Young generation)

    • 常规的对象分配
    • 由于存活对象很少,可以采用 copying collection 策略
    • GC 吞吐率很高
  • 老年代(Old generation)

    • 对象趋向于一直存活,反复复制开销较大
    • 可以采用 mark-sweep collection 策略
引用计数(ARC)

引用计数是另一种 GC 策略,在这种策略下,每个对象都有一个与之关联的引用数目,只有引用数大于 0 的对象才存活。

image.png

⭐引用计数的优点:

  • 内存管理的操作被平摊到程序的执行过程中;
  • 内存管理不需要了解 runtime 的实现细节。

👎引用计数的缺点:

  • 维护引用计数的开销较大:通过原子操作保证对引用计数操作的原子性和可见性;
  • 无法回收环形数据结构(循环引用) —— weak reference;
  • 额外的内存开销:每个对象都引入额外的内存空间存储引用数目;
  • 回收内存时依然可能引发暂停。

image.png

✨引用计数 vs. 其他策略:

时机性能延迟
ARC引用计数为 0 马上回收
other GC定时扫描清理

Go 内存分配

Go 的内存分配基于两个思想:分块 & 缓存。

分块

Go 会提前将内存分块,给对象分配内存时会找一个尺寸最接近的块分配。

🎯目标: 为对象在堆(heap)上分配内存。

✔内存分块:

  • 调用系统调用 mmap() 向 OS 申请一大块内存,例如 4MB;
  • 先将内存划分成大块,例如 8KB,称作 mspan;
    • noscan mspan:分配不包含指针的对象(GC 不需要扫描)
    • scan mspan:分配包含指针的对象(GC 需要扫描)
  • 再将大块继续划分成特定大小的小块,用于对象分配。

🍬对象分配: 根据对象的大小,选择最合适的块返回。

image.png

缓存(cache)

Go 的内存分配器为内存做了多级不同的缓存,从而加快整体的内存分配速度。

线程缓存分配(Thread-Caching Malloc,TCMalloc)是用于分配内存的机制,Go 语言的内存分配器就借鉴了 TCMalloc 的设计实现高速的内存分配,它的核心理念是使用多级缓存将对象根据大小分类,并按照类别实施不同的分配策略。

image.png

☕分配过程:

  • 分配内存是指给 goroutine(简称为 g) 上的一段代码分配内存,g 会先绑定在 p(Go 线程)上;
  • 每个 p 包含一个 mcache 用于快速分配,用于为绑定与 p 上的 g 分配对象;
  • mcache 管理一组 mspan;
  • 当 mcache 中的 mspan 分配完毕,向 mcentral 申请带有未分配块的 mspan;
  • 当 mspan 中没有分配的对象,mspan 会被缓存在 mcentral 中,而不是立刻释放并归还给 OS。

image.png


Go 语言中的 GC 策略

了解了这么多内存管理的相关知识和垃圾回收策略,下面来一起看看 Golang 中采用的垃圾回收策略。

Go 语言的垃圾回收总体采用的是经典的 mark-sweep 算法,Go 语言的版本不同,采用的 GC 策略可能是不一样的。Go 1.5 正在实现的垃圾回收器是 “非分代的、非移动的、并发的、三色的标记清除垃圾收集器”。

Go 1.5 使用的三色标记法可以看成 mark-sweep 的增强版,这种方法的 mark 操作是可以渐进执行的而不需每次都扫描整个内存空间,,可以减少 stop the world(STW)的时间;分代 GC 策略在上文已经提及,但是 Go 1.5 还暂时没有采用,Go 官方表示会在 1.6 版本的 GC 优化中考虑~

随着 Golang 的推陈出新,Go 的垃圾回收性能一直在提升,但目前距离 Java 语言的 JVM 使用的成熟的垃圾回收系统还有一定差距。


Go 内存管理优化

Go 内存分配机制中的问题

对象分配是非常高频的操作,每秒分配 GB 级别的内存,小对象占比又比较高,加上分配路径长,这就导致 Go 内存分配比较耗时。

  • 分配路径长:g->m->p->mcache->mspan->memory block->return pointer
  • pprof():对象分配的函数是最频繁调用的函数之一
字节的优化方案:Balanced GC

Balanced GC 是字节跳动官方推出的针对 Go SDK 里面对象分配做的优化方案。

  • 每个 g 都绑定一大块内存(1KB),称作 goroutine allocation buffer(GAB);
  • GAB 用于 noscan 类型的小对象分配:< 128 B
  • 使用三个指针维护 GAB:base,end,top;
  • Bump pointer(指针碰撞)风格对象分配:无须和其他分配请求互斥,分配动作简单高效。

image.png

// 一次对象分配:
if top + size <= end {addr := toptop += sizereturn addr
}

💭技术细节:

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

  • 本质:将多个小对象的分配合并成一次大对象的分配。
  • 问题:GAB 的对象分配方式会导致内存被延迟释放。
  • 方案:移动 GAB 中存活的对象(用 copying GC 的算法管理小对象)
    • 当 GAB 总大小超过一定阈值时,将 GAB 中存活的对象复制到另外分配的 GAB 中;
    • 原先的 GAB 可以释放,避免内存泄漏。

Balanced GC 作为语言层面的性能优化,开启以后可以减少 CPU 负荷,降低核心接口时延,获得不错的性能收益。

相关文章:

深入浅出 Golang 内存管理

了解内存管理~ 前言&#xff1a; 本节课主要介绍了内存管理知识与自动内存管理机制&#xff0c;并对目前 Go 内存管理过程中存在的问题提出了解决方案&#xff0c;同时结合了上次课程学习的《Go 语言性能优化》相关知识&#xff0c;提供可行性的优化建议 … 自动内存管理 Go…...

基于Python的简单40例和爬虫详细讲解(文末赠书)

目录 先来看看Python40例 学习Python容易坐牢&#xff1f; 介绍一下什么是爬虫 1、收集数据 2、爬虫调研 3、刷流量和秒杀 二、爬虫是如何工作的&#xff1f; 三、爬虫与SEO优化 什么是python爬虫 Python爬虫架构 最担心的问题 本期送书 随着人工智能以及大数据的兴起…...

Vector - CAPL - CAN x 总线信息获取(续2)

继续.... 目录 ErrorFrameCount -- 错误帧数量 代码示例 ErrorFrameRate -- 错误帧速率 代码示例 ExtendedFrameCount -- 扩展帧数量 代码示例 ExtendedFrameRate -- 扩展帧速率 代码示例 ExtendedRemoteFrameCount -- 远程扩展帧数量 代码示例 ExtendedRemoteFrameRa…...

C++基础知识【8】模板

目录 一、什么是C模板&#xff1f; 二、函数模板 三、类模板 四、模板特化 五、模板参数 六、可变模板参数 七、模板元编程 八、嵌套模板 九、注意事项 一、什么是C模板&#xff1f; C模板是C编程中非常重要的一部分&#xff0c;它允许程序员以一种通用的方式编写代码…...

MAC-安装Java环境、JDK配置、IDEA插件推荐

背景&#xff1a;发现经常换电脑装环境等比较麻烦&#xff0c;主要还是想记录一下&#xff0c;不要每次安装都到处翻。。 1、下载并安装JDK 到官网下载所需的JDK&#xff1a;https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html 这儿下…...

Mysql如何避免常见的索引失效

Mysql索引算是非常常用了&#xff0c;用得好提高效率&#xff0c;用的不好适得其反 如何避免常见的索引失效 1.模糊查询 使用 LIKE 查询时&#xff0c;如果搜索表达式以通配符开头&#xff0c;如 %value&#xff0c;MySQL 就无法使用索引来加速查询&#xff0c;因为它无法倒序…...

SpringBoot集成Redis及问题解决

SpringBoot集成Redis 此篇文章为SpringBoot集成Redis的简单介绍&#xff0c;依赖、序列化操作、工具类都可以在后面的实操中直接搬运使用或者在此基础上进行改进使用 1、集成Redis 1.1、新建SpringBoot项目 新建项目这边就不一一介绍了&#xff0c;大家如果还有不会的可以自行…...

PyTorch 人工智能研讨会:6~7

原文&#xff1a;The Deep Learning with PyTorch Workshop 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心…...

AI绘图设计师Stable Diffusion成为生产力工具(五):放大并修复老照片、马赛克照片、身份证件照

S&#xff1a;你安装stable diffusion就是为了看小姐姐么&#xff1f; I &#xff1a;当然不是&#xff0c;当然是为了公司的发展谋出路~~ 预先学习&#xff1a; 安装webui《Windows安装Stable Diffusion WebUI及问题解决记录》。运行使用时问题《Windows使用Stable Diffusion时…...

cubase正版下载安装包-cubase正版下载v1.2.0.69 软件激活版

cubase正版下载是一款实用的音乐创作类软件。我们可以通过这款软件实现创作音乐的自由&#xff0c;再也不用花大价钱请别人来帮忙制作&#xff0c;只需自己动动手就可以轻松完成我们所想要的&#xff0c;这款软件做到了让每一位热爱音乐的人都可以实现自己的梦想。 cubase正版…...

Python机器学习:支持向量机

这是我读本科的时候第一个接触到的机器学习算法&#xff0c;但也是第一个听完就忘的。。。 他的基本思想很简单&#xff1a;想办法把一个样本集划成两个部分&#xff1a;对于空间中的样本点集合&#xff0c;我们找到一个超平面把这个样本点集合给分成两个部分&#xff0c;其中…...

矩阵和线性代数的应用

矩阵和线性代数是数学中重要的概念&#xff0c;它们被广泛应用于物理、工程、计算机科学、经济学等众多领域。本文将讨论矩阵和线性代数的一些基本概念以及它们在实际应用中的重要性和影响。 一、矩阵和线性代数的基本概念 矩阵是由数字组成的矩形数组。它可以表示线性方程组…...

六:内存回收

内存回收&#xff1a; 应用程序通过 malloc 函数申请内存的时候&#xff0c;实际上申请的是虚拟内存&#xff0c;此时并不会分配物理内存。 当应用程序读写了这块虚拟内存&#xff0c;CPU 就会去访问这个虚拟内存&#xff0c; 这时会发现这个虚拟内存没有映射到物理内存&…...

【cpolar 内网穿透】Openwrt 软路由实现内网穿透

cpolar 是一种安全的内网穿透云服务&#xff0c;它将内网下的本地服务器通过安全隧道暴露至公网。使得公网用户可以正常访问内网服务。 文章目录 前言一、上传 cpolar 安装包二、配置cpolar环境变量三、安装并配置 cpolar 服务3.1 安装 cpolar3.2 启动 cpolar3.3 进行其他配置 …...

Android 10.0 Camera2 拍照功能默认选前摄像头

1.概述 在10.0的系统产品开发中,对于app调用系统api来打开摄像头拍照的功能也是常有的功能,而拍照一般是默认打开后置摄像头拍照的,由于 客户的产品特殊要求,需要打开前置摄像头拍照功能,所以需要了解拍照功能的流程,然后修改默认前置摄像头打开拍照功能就可以了 app调…...

vue-vue2和vue3的diff算法

核心要点 数据变化时&#xff0c;vue如何更新节点虚拟DOM 和 真实DOM 的区别vue2 diff 算法vue3 diff 算法 一、 数据变化时&#xff0c;vue如何更新节点 首先渲染真实DOM的开销是很大&#xff0c;比如有时候我们修改了某个数据且修改的数据量很大时&#xff0c;此时会频繁的…...

一文解读基于PaddleSeg的钢筋长度超限监控方案

项目背景 钢铁厂生产钢筋的过程中会存在部分钢筋长度超限的问题&#xff0c;如果不进行处理&#xff0c;容易造成机械臂损伤。因此&#xff0c;需要通过质检流程&#xff0c;筛选出存在长度超限问题的钢筋批次&#xff0c;并进行预警。传统的处理方式是人工核查&#xff0c;该方…...

NumPy 数组学习手册:1~5

原文&#xff1a;Learning NumPy Array 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 一、NumPy 入门 让我们开始吧。 我们将在不同的操作系统上安装 NumPy 和相关软件&#xff0c;并查看一些使用 NumPy 的简单代码。 正如“序言”所述&#xff0c;SciPy 与 NumPy 密…...

【C++11】晦涩难懂语法系列:可变参数模板

目录 可变参数模板 1.1 概念 1.2 可变参数模板定义 1.3 参数包的展开方式 1.3.1 递归展开参数包 1.3.2 逗号表达式展开参数包 1.4 STL的emplace系列函数 可变参数模板 1.1 概念 在C语言阶段&#xff0c;我们已经接触过可变参数&#xff0c;比如scand、printf等等 这里…...

计算机组成原理第二章——数据的表示与运算(下)

提示&#xff1a;时光清浅处 一步一安然 文章目录 前言2.3.1 浮点数的表示2.3.2 IEEE7542.2.3 浮点数的运算 前言 本节主要讲三个问题&#xff0c;浮点数的表示&#xff0c;IEEE 754标准&#xff0c;浮点数的加减运算 2.3.1 浮点数的表示 浮点数的作用和基本原理 定点数可表…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架&#xff0c;专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用&#xff0c;其中包含三个使用通用基本模板的页面。在此…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...