Golang内存、指针逃逸、垃圾回收机制概览

最近看到了一篇文章是关于go的内存、指针逃逸和垃圾回收机制的,发现自己并未很细致的了解过这方面的内容,于是在翻阅各种文章的情况下,写出了这篇总结,参考文章放在文末,可自取

内存

Go 语言使用一个自带的垃圾收集器(Garbage Collector, GC)来自动管理内存,这意味着程序员不需要直接参与内存的分配和释放,这减少了内存泄漏和其他内存相关错误的可能性。Go 中的内存可以分为两个主要部分:

  1. 栈(Stack):栈通常存储大小生命周期是能被预估的数据。函数内的局部变量和返回值;管理采用先进后出的模式,不需要复杂的垃圾回收机制;栈的特点是拥有非常高的访问速度和较低的内存分配开销,但空间有限。
  2. 堆(Heap):用于存储运行时可能变化的数据,或函数作用域之外需要访问的数据;更大规模的内存区域,用于存储生命周期较长或大小无法预知的数据。堆内存的分配和回收成本相对较高,但可以动态地扩展。

可以通过以下命令来分析应用程序:

go build -gcflags=-m main.go

指针逃逸

指针逃逸分析是 Go 编译器进行的一种优化。通过这种分析,编译器确定变量的存储位置(栈还是堆)。如果一个变量在函数结束后仍然可以被访问(例如,被其他函数引用或返回给调用者),这个变量就会从栈“逃逸”到堆。

指针逃逸的主要影响是性能:

  • 栈分配的变量:当函数调用结束时,这些变量的内存可以立即被清理,这一过程非常快速且高效。
  • 堆分配的变量:需要垃圾收集器介入来回收这部分内存,这可能导致额外的性能开销。

深入理解指针逃逸

在 Go 中,编译器进行逃逸分析是为了决定数据应当存放在堆上还是栈上。我们已经知道,存放在栈上的数据有着更快的访问速度和更简单的生命周期管理,但栈的空间有限且仅在函数执行期间存在。相反,堆上的数据可以在函数执行完毕后继续存在,但其管理成本较高,因为涉及到复杂的垃圾回收机制。

何时发生逃逸?

  1. 返回局部变量的地址:如果函数返回局部变量的指针,这个变量就会从函数的栈帧中逃逸到堆,因为局部变量的生命周期必须延长到函数外部。
  2. 大对象:即使对象没有被外部引用,如果对象非常大,它可能也会被分配到堆上,以避免栈溢出。
  3. 动态类型:如接口或含有接口的类型。由于接口的动态特性,编译器可能无法预测具体的实现类型和大小,因此可能选择将其分配到堆上。
  4. 闭包:引用外部函数局部变量的闭包可能导致这些变量逃逸,因为这些变量必须在闭包存在时继续存在。

优化技巧

理解和优化指针逃逸可以使得 Go 程序更加高效。以下是一些常见的优化技巧:

  • 避免不必要的堆分配:尽量使用局部变量和传值,避免在不必要的情况下创建指针。
  • 使用对象池:对于频繁使用和创建的对象,可以使用 sync.Pool 来复用对象,减少垃圾收集的负担。
  • 分析逃逸情况:使用 go build -gcflags="-m" 命令来查看编译器的逃逸分析结果,了解哪些变量逃逸到堆,并探索优化方法。
  • 配置垃圾收集器:通过设置 GOGC 环境变量(默认值是 100),可以调整垃圾收集器的敏感度。增加这个值会减少垃圾收集的频率,可能增加程序的整体内存使用,但可以减少因垃圾收集引起的延迟。

垃圾回收机制

Go语言的垃圾回收(GC)机制是一种自动内存管理的实现,它旨在帮助程序开发者免除手动管理内存的复杂性。Go的垃圾回收器主要基于“标记-清扫”(Mark-and-Sweep)算法,但随着版本的更新,Go团队已经对其进行了优化和改进,引入了并发的执行和更多的性能优化措施。Go的GC实现的特点是并发执行,且尽量减少对程序执行的干扰。

overview

设计原则

Go的垃圾回收器设计目标是简化并发程序的内存管理,同时实现以下几个关键目标:

  1. 效率:尽量减少GC的CPU和内存开销。
  2. 并发:GC过程与用户程序并发执行,减少STW(Stop-The-World)的影响。
  3. 实时性:保证程序的响应时间,通过减少GC引起的延迟。

垃圾回收器

垃圾回收器中的变量通常分为以下三类:

  • 活动堆内存(在上一次垃圾回收周期中标记为“活动”的内存)
  • 新堆内存(尚未由垃圾回收器分析的堆内存)
  • 内存用于存储一些元数据,通常与前两个实体相比微不足道。

垃圾回收器的CPU时间消耗与其工作特性有关。有一种称为“全停顿”的垃圾回收器实现,它会在垃圾回收期间完全停止程序执行,导致CPU时间用于非生产性工作。

在Go的情况下,垃圾回收器并非完全“全停顿”,并且在应用程序执行过程中并行执行大部分工作,例如堆标记。

然而,垃圾回收器仍然有一些限制,并且在一个周期内多次完全停止执行工作代码。

垃圾收集的性能开销和内存使用效率直接关联到逃逸分析的结果。减少堆分配可以显著降低垃圾收集的频率和延迟,从而提高程序的整体性能。

核心算法

Go 的垃圾收集器是一个实现了三色标记清除算法的并发收集器。垃圾收集过程主要分为以下几个阶段:

初始化阶段

GC的启动通常由内存分配触发,当分配的总内存量达到当前堆大小的一定比例(由**GOGC**环境变量控制,默认为100%)时,GC开始工作。

标记阶段(Mark Phase)

在这一阶段,垃圾回收器通过从根对象(如全局变量和当前所有Goroutine的栈)出发,标记所有可达的对象。Go使用写屏障(write barrier),在运行时对对象进行标记,这有助于垃圾回收器在应用程序运行时并发执行。

  • 三色抽象:使用黑色、灰色和白色来代表不同状态的对象:
    • 黑色:对象及其子对象都已经被扫描,不会再引用新的白色对象。
    • 灰色:对象被标记为存活,但其子对象还未扫描完。
    • 白色:对象未被访问,可能是垃圾。

gif

清扫阶段(Sweep Phase)

标记完成后,GC进入清扫阶段。在这个阶段,GC遍历堆中的所有对象,释放那些标记为白色的对象所占用的内存。清扫阶段通常也是并发进行,不会中断程序的正常执行。

如何管理垃圾回收器

有一个参数允许您在Go中管理垃圾回收器:GOGC环境变量或其功能等效项SetGCPercent,来自runtime/debug包。

GOGC参数决定了在触发垃圾回收时相对于活动内存的新未分配堆内存的百分比。

GOGC的默认值为100,这意味着当新内存的数量达到活动堆内存的100%时,将触发垃圾回收。

优化和改进

并发垃圾回收

Go的GC从版本1.5开始实施并发标记,这显著降低了STW的时间。在最近的版本中,Go团队进一步减少了GC操作中必须停止程序执行的时间。

写屏障

写屏障是用来维护GC标记正确性的技术。当程序运行时修改对象引用时,写屏障确保这些改动不会破坏正在进行的垃圾回收过程。Go使用的是混合写屏障,它在GC期间启用,有助于标记阶段的并发执行。

调节和配置

  • GOGC环境变量:通过设置这个环境变量,开发者可以控制GC触发的频率。增大这个值会增加堆的允许大小,从而减少GC的频率,反之亦然。
  • runtime/debug 包:提供了更细粒度的控制,比如**SetGCPercent**函数允许在运行时调整GC的触发阈值。

性能考量

尽管Go的GC是高度优化的,但在内存密集或延迟敏感的应用中,GC仍可能成为性能瓶颈。开发者需要通过剖析工具(如pprof)定期检查GC的性能影响,并适当调整GC配置以优化应用性能。

参考文章

  1. Golang垃圾回收(GC)介绍
  2. Memory Optimization and Garbage Collector Management in Go

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/313819.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOV5 TensorRT部署 BatchedNMS(engine模型推理)(下)

主要是在王新宇代码的基础上改进,引入对BatchedNMS的解码 文章目录 1. 修改yolov5.cpp2.修改yololayer.h1. 修改yolov5.cpp 首先增加全局变量,名字根据转onnx时修改的节点名字来,查看onnx文件可以看到,顺序不要弄错。 const char *INPUT_NAME = “images”; const char …

Aigtek:介电弹性体高压放大器在软体机器人研究中的应用

近年来软体机器人的研究成为目前机器人研究领域的热点,由于软体材料的自由度可以根据需求自由变化,因此软体机器人有着极高的灵活性,而且软体机器人因其材料的柔软性有着很好的人机交互性能和安全性。它的出现成功解决了传统的刚性机器人人机…

ArcGIS Pro专题地图系列教程

专题地图系列是ArcGIS Pro3.2的新功能。之前,如果要做8张相同区域的专题图,可能需要新建8个布局,分别进行排版,再导出。现在,一幅地图,一个布局,就可以完成这个流程。 原理是,根据单…

AI预测福彩3D第9套算法实战化测试第4弹2024年4月26日第4次测试

今天继续进行新算法的测试,今天是第4次测试。好了,废话不多说了,直接上图上结果。 2024年4月26日福彩3D预测结果 6码定位方案如下: 百位:4、5、7、8、3、9 十位:6、9、5、4、1、2 个位:7、8、5、…

PostgreSql-Install

PostgreSql源码安装 一、源代码下载二、操作系统配置三、编译安装四、启动数据库五、相关命令 PostgreSQL是一个强大的 开源对象关系数据库系统,它使用并扩展了SQL语言,并结合了许多功能,可以安全地存储和扩展最复杂的数据工作负载。 一、源…

npm install 卡在still idealTree buildDeps不动

前言 再使用npm install 安装包依赖时 发现一直卡住 停留在 观察node_cache下的_logs文件 发现一直在拉取包 37 silly idealTree buildDeps 38 silly fetch manifest riophae/vue-treeselect0.4.0尝试解决 尝试设置了taobao镜像源 依然如此 获取已经设置的镜像源 确实是ta…

高级数据结构—线段树(一)

学线段树的原因是因为cf的一道题目始终想不出来怎么优化,后来知道区间查询和修改要用到线段树。。。 原题:Iva & Pav 线段树的作用 区间最值查询:可以高效地找到给定区间内的最大值、最小值等。 区间和查询:可以高效地计算…

关于MCU核心板的一些常见问题

BGA植球与焊接(多涂焊油): 【BGA芯片是真麻烦,主要是植锡珠太麻烦了,拆一次就得重新植】https://www.bilibili.com/video/BV1vW4y1w7oNvd_source3cc3c07b09206097d0d8b0aefdf07958 / NC电容一般有两种含义&#xff1…

Python爱心代码

爱心效果图: 完整代码: import random from math import sin, cos, pi, log from tkinter import *# 定义画布尺寸和颜色 CANVAS_WIDTH 640 CANVAS_HEIGHT 480 CANVAS_CENTER_X CANVAS_WIDTH / 2 CANVAS_CENTER_Y CANVAS_HEIGHT / 2 IMAGE_ENLARG…

AI容器化部署开发尝试 (一)(Pycharm连接docker,并部署django测试)

目标:使用容器化技术快速部署AI应用进行开发。 注意:从 Docker 19.03 开始,Docker 引入了对 NVIDIA GPU 的原生支持,因此若AI要调用GPU算力的话docker版本也是有要求的,后面博客测试。 当然本篇博客还没设计到GPU的调…

微服务两种方式登录

目录 1.restTemplate方式 1.1页面 1.2消费者 1.3生产者 1.4效果 2.Feign方式 2.1Service 2.2生产者 三个生产者 一个消费者,三个生产者需要用mysqlmybatis 三个不同的数据库。 页面输入用户名和密码,提交到后端消费者,消费者传到生产…

vLLM-prefix浅析(System Prompt,大模型推理加速)

原文:vLLM-prefix浅析(System Prompt,大模型推理加速) 简介 本文浅析了在大模型推理加速方面一个非常优秀的项目 vLLM 的一个新特性 Prefix。在 Prompt 中有相同前缀时可以提高吞吐量降低延迟,换句话说可以省去这部分…

【C++】:构造函数和析构函数

目录 前言一,构造函数1.1 什么是构造函数1.2 构造函数的特性1.3 总结 二,析构函数2.1 什么是析构函数2.2 析构函数的特性2.3 总结 前言 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何…

JVM学习笔记(五)内存模型

目录 1、原子性 1.1 问题分析 1.2 解决方法 2、可见性 2.1 退不出的循环 2.2 解决办法 3、有序性 3.1 诡异的结果 3.2 解决办法 3.3 有序性理解 3.4 happens-before 4、CAS与原子类 4.1 CAS 4.2 乐观锁与悲观锁 4.3 原子操作类 5、synchronized 优化 5.1 轻量…

华为认证云计算前景如何

互联网/移动互联网经历了高速发展的二十年,我们有幸一起见证了华为、阿里、腾讯、百度、字节跳动、京东、滴滴、拼多多等互联网公司的崛起,让普通技术人实现逆袭拿到高薪,也让小镇做题家们有了阶层跨越的机会。 但机会都是留给有准备的人&…

记录一个hive中因没启yarn导致的spark引擎跑insert语句的报错

【背景说明】 刚在hive中配置了Spark引擎,在进行Hive on Spark测试时报错, 报错截图如下: [atguiguhadoop102 conf]$ hive which: no hbase in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/module/jdk1.8.0_212/bin:/opt/mod…

分享三个转换速度快、准确率高的视频转文字工具

想要直接将视频转换成文字,转换工具很重要!给大家分享三个转换速度快、准确率高的视频转文字工具,轻松完成转换。 1.网易见外 https://sight.youdao.com/ 网易家的智能转写翻译服务工作站,网页端就可以直接使用,支持视…

【threejs教程7】threejs聚光灯、摄影机灯和汽车运动效果

【图片完整效果代码位于文章末】 在上一篇文章中我们实现了汽车模型的加载,这篇文章主要讲如何让汽车看起来像在运动。同时列出聚光灯和摄像机灯光的加载方法。 查看上一篇👉【threejs教程6】threejs加载glb模型文件(小米su7)&…

Web3钱包开发获取测试币-Base Sepolia(二)

Web3钱包开发获取测试币-Base Sepolia(二) 基于上篇 Web3钱包开发获取测试币-Polygon Mumbai(一) :https://suwu150.blog.csdn.net/article/details/137949473 我们今天来说说Base Sepolia网络的添加。 一、添加Base Sepolia到钱包 什么是Base Sepolia&#xff1f…

如何在PostgreSQL中使用索引覆盖扫描提高查询性能?

文章目录 解决方案1. 创建合适的索引2. 确保查询能够使用索引覆盖扫描3. 调整查询以利用索引覆盖扫描4. 监控和调优 示例代码1. 创建索引2. 编写查询3. 检查是否使用索引覆盖扫描4. 调整索引 总结 在PostgreSQL中,索引是提高查询性能的关键工具之一。索引允许数据库…