深入探索 Go 语言的编译器与垃圾回收机制
Go 编译器
Go 编译器是通过 go 工具执行的,这个工具的功能不仅仅是生成可执行文件。你可以使用 go tool compile 命令来编译一个 Go 源文件。这个操作将生成一个目标文件,也就是 .o 后缀的文件。以下是在 macOS Mojave 系统上执行的命令和结果展示:
$ go tool compile unsafe.go
$ ls -l unsafe.o
-rw-r--r-- 1 mtsouk staff 6926 Jan 22 21:39 unsafe.o
$ file unsafe.o
unsafe.o: current ar archive
目标文件是一种包含机器代码的文件,通常是不可直接执行的。它的一个主要优势在于在链接阶段所需的内存更少。如果你使用 -pack 命令行参数,go tool compile 会生成一个归档文件,而不是目标文件:
$ go tool compile -pack unsafe.go
$ ls -l unsafe.a
-rw-r--r-- 1 mtsouk staff 6926 Jan 22 21:40 unsafe.a
$ file unsafe.a
unsafe.a: current ar archive
归档文件是一种二进制文件,包含一个或多个文件,主要用于将多个文件合并为一个文件。ar 是其中一种格式,Go 使用的就是这种格式。这个示例中的 unsafe.go 文件不包含任何特殊代码,以上的命令适用于任何有效的 Go 源文件。
查看归档文件内容
你可以使用以下命令查看 .a 归档文件的内容:
$ ar t unsafe.a
__.PKGDEF
_go_.o
-race 标志
另一个值得一提的 go tool compile 命令行参数是 -race,它可以检测竞态条件。在并发编程中,竞态条件可能导致意想不到的错误。你可以通过以下命令生成汇编语言的输出:
$ go tool compile -S unsafe.go
这个命令会生成大量的输出,虽然它难以理解,但这意味着 Go 编译器很好地隐藏了复杂性,除非你主动要求查看这些细节。
垃圾回收
垃圾回收(GC)是释放未被使用的内存空间的过程,换句话说,GC 会找到那些已经超出作用范围且无法再被引用的对象,并释放它们占用的内存空间。这个过程是在 Go 程序运行时以并发方式执行的,而不是在程序执行前或执行后才开始。Go 垃圾回收的官方文档中提到:
“GC 与变更线程并发运行,精确类型化(也称为精确),允许多个 GC 线程并行运行。它是并发标记-清除,使用写屏障,非代际且非压缩。分配采用大小分离的每 P 分配区,以最小化碎片化,同时在常见情况下消除锁。”
其中涉及到许多术语,接下来我们会逐一解释。首先,我会展示一个查看垃圾回收过程参数的方法。
使用标准库查看垃圾回收参数
幸运的是,Go 标准库提供了一些函数,可以帮助我们了解垃圾回收的运行方式。下面的代码展示了如何获取垃圾回收的相关信息:
package mainimport ("fmt""runtime""time"
)func printStats(mem runtime.MemStats) {runtime.ReadMemStats(&mem)fmt.Println("当前内存分配:", mem.Alloc)fmt.Println("内存总分配:", mem.TotalAlloc)fmt.Println("堆内存分配:", mem.HeapAlloc)fmt.Println("垃圾回收次数:", mem.NumGC)fmt.Println("-----")
}
每当你需要获取最新的垃圾回收统计信息时,你需要调用 runtime.ReadMemStats() 函数。printStats() 函数用于打印这些信息,以避免重复编写相同的代码。
接下来的部分创建了大量的 Go 切片,以分配大量内存并触发垃圾回收:
func main() {var mem runtime.MemStatsprintStats(mem)for i := 0; i < 10; i++ {s := make([]byte, 50000000)if s == nil {fmt.Println("操作失败!")}printStats(mem)}
}
最后一部分代码做了更多的内存分配操作:
for i := 0; i < 10; i++ {s := make([]byte, 100000000)if s == nil {fmt.Println("操作失败!")}time.Sleep(5 * time.Second)
}
printStats(mem)
运行上述代码的输出如下(以 macOS Mojave 为例):
$ go run gColl.go
当前内存分配: 66024
内存总分配: 66024
堆内存分配: 66024
垃圾回收次数: 0
-----
当前内存分配: 50078496
内存总分配: 500117056
堆内存分配: 50078496
垃圾回收次数: 10
-----
当前内存分配: 76712
内存总分配: 1500199904
堆内存分配: 76712
垃圾回收次数: 20
-----
深入理解垃圾回收
观察垃圾回收的行为能够帮助你在性能较慢的应用中发现问题。你可以通过以下命令查看更详细的 GC 信息:
$ GODEBUG=gctrace=1 go run gColl.go
输出会显示每次垃圾回收的详细数据。例如:
gc 4 @0.025s 0%: 0.002+0.065+0.018 ms clock, 47->47->0 MB, 48 MB goal
三色标记-清除算法
Go 的垃圾回收基于三色标记-清除算法。这个算法将堆中的对象分为三类:白色、灰色和黑色。白色对象是垃圾回收的候选对象,而灰色对象可能指向白色对象,黑色对象则不会指向白色对象。
当垃圾回收开始时,所有对象最初是白色的,垃圾回收器会将根对象标记为灰色,并继续扫描灰色对象。如果灰色对象指向白色对象,它会将这些白色对象标记为灰色,最终所有不可达的白色对象会被回收。
在程序运行过程中,如果某个对象变得可达,写屏障机制会将其重新标记为灰色,确保其不会被错误回收。
这个三色标记-清除算法不仅适用于 Go,还可以应用于其他编程语言。
相关文章:
深入探索 Go 语言的编译器与垃圾回收机制
Go 编译器 Go 编译器是通过 go 工具执行的,这个工具的功能不仅仅是生成可执行文件。你可以使用 go tool compile 命令来编译一个 Go 源文件。这个操作将生成一个目标文件,也就是 .o 后缀的文件。以下是在 macOS Mojave 系统上执行的命令和结果展示&…...
2024国赛数学建模-模拟火算法(MATLAB 实现)
模拟退火算法 1.1 算法原理 模拟退火算法的基本思想是从一给定解开始 ,从邻域 中随机产生另一个解 ,接受 Metropolis准则允许目标函数在 有限范围内变坏 ,它由一控制参数 t决定 ,其作用类似于物 理过程中的温度 T,对于控制参数的每一取值 ,算法持续进 行“产生 —判断 —接受…...
YOLOv8 只检测人 只画框不要标签
参考了这个:YOLOv8只检测人(或其他一种或者多种类别)_yolov8只检测指定类别-CSDN博客 1. 只检测人:predict的时候指定参数classes[0] 2. 只画框不要标签:plot的时候传入labelsFalse 3. 标签中去掉置信度:…...
如何将网络安全防范游戏化
组织对威胁的准备和恢复能力跟不上网络犯罪分子的进步。 一些首席执行官仍然认为网络安全需要偶尔干预,而不是持续关注。 但对于许多公司来说,情况并非如此;网络威胁准备需要协调一致的培训工作,因此网络安全团队在攻击发生时已…...
Qt QGraphicsView实现图片放缩、鼠标拖动移动、鼠标点位置放大缩小_图片查看
QtQGraphicsView实现图片放缩、鼠标拖动移动、鼠标点位置放大缩小 头文件: #ifndef TIMGWIDGET_H #define TIMGWIDGET_H#include <QGraphicsItem> #include <QMainWindow> #include <QObject> #include <QWidget>// class TImgWidget : pu…...
Percona Toolkit 神器全攻略(复制类)
Percona Toolkit 神器全攻略(复制类) Percona Toolkit 神器全攻略系列共八篇,前文回顾: 前文回顾Percona Toolkit 神器全攻略Percona Toolkit 神器全攻略(实用类)Percona Toolkit 神器全攻略(配…...
SQLite3 数据类型深入全面讲解
SQLite3,作为一款轻量级的数据库管理系统,在数据存储方面展现出了其独特的魅力。它不仅支持标准的SQL语法,还提供了丰富的数据类型供开发者选择。这些数据类型不仅涵盖了基本的数值和文本类型,还包括了日期时间、二进制数据等复杂…...
Python高效实现Trie(前缀树)及其插入和查找操作
Python高效实现Trie(前缀树)及其插入和查找操作 在Python面试中,考官通常会关注候选人的编程能力、问题解决能力以及对Python语言特性的理解。Trie(前缀树)是一种高效的数据结构,广泛应用于字符串处理、自动补全、拼写检查等场景。本文将详细介绍如何实现一个Trie,并提…...
傅里叶变换家族
禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》 禹晶、肖创柏、廖庆敏《数字图像处理》资源二维码...
深度学习——强化学习算法介绍
强化学习算法介绍 强化学习讨论的问题是一个智能体(agent) 怎么在一个复杂不确定的环境(environment)里面去极大化它能获得的奖励。 强化学习和监督学习 强化学习有这个试错探索(trial-and-error exploration),它需要通过探索环境来获取对环境的理解。强化学习 ag…...
轴承知识大全,详细介绍(附3D图纸免费下载)
轴承一般由内圈、外圈、滚动体和保持架组成。对于密封轴承,再加上润滑剂和密封圈(或防尘盖)。这就是轴承的全部组成。 根据轴承使用的工作状况来选用不同类型的轴承,才能更好的发挥轴承的功能,并延长轴承的使用寿命。我…...
【PyTorch】基础环境如何打开
前期安装可以基于这个视频,本文是为了给自己存档如何打开pycharm和jupyter notebookPyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】_哔哩哔哩_bilibili Pycharm 配置 新建项目的时候选择解释器pytorch-gpu即可。 Jupyte…...
QT教程:QTime和QTimer的使用场景
QTime类 QTime 是一个用来表示和操作时间的类,它处理一天中的具体时间(例如小时、分钟、秒、毫秒)。通常用于计算时间间隔、记录时间戳、获取当前时间等。 特点和功能 表示时间:QTime 用来表示一天中的某个具体时间(小…...
MySQL 迁移中 explicit_defaults_for_timestamp 参数影响
前言 最近在做数据迁移的时候,使用的是云平台自带的同步工具,在预检查阶段,当时报错 explicit_defaults_for_timestamp 参数在目标端为 off 建议修改 on,有什么风险呢?在此记录下。 测试对比 MySQL 默认情况下 expl…...
树状数组记录
树状数组(Fenwick Tree)是一种用于维护数组前缀和的数据结构,支持高效的单点更新和区间查询操作。它的查询和更新时间复杂度为 O ( log n ) O(\log n) O(logn),适用于需要频繁更新和查询的场景。 树状数组的基本操作 单点更…...
客户端时间和服务器时间的区别
客户端时间: 服务器向客户端拷贝一份前端内容,客户端通过JS获取时间,这样获取的是客户端时间 服务器时间: 服务器通过java代码获取的时间传输给客户端,这样获取的是服务器时间 当有些时候需要使用客户端时间…...
已入职华为!!关于我成功拿下华为大模型算法岗经验总结
方向:大模型算法工程师 整个面试持续了1小时10分钟,能够看出面试官是典型搞技术的,问的很专业又很细,全程感觉压力好大,面完后感觉丝丝凉意,不过幸好还是成功拿下了Offer 一面: 自我介绍 简历项目深度交流 1.项目的背…...
从安卓开发到AI产品经理——我的AI绘画之旅
大家好,我是一名有着多年安卓开发经验的程序员。在日复一日的编码生活中,我对AI行业产生了浓厚的兴趣。于是,我决定转行成为一名AI产品经理。在这个过程中,我通过学习AI绘画工具初步了解了AI行业,下面我将分享我的学习…...
代码随想录八股训练营第三十四天| C++
前言 一、vector和list的区别? 1.1.存储方式: 1.2.随机访问: 1.3.插入和删除操作: 1.4.内存使用: 1.5.容量和大小: 1.6.迭代器类型: 1.7.用途: 二、vector 底层原理和扩容过…...
《深入理解 Java 中的 this 关键字》
目录 一、this关键字的基本理解 二、this调用属性和方法 (一)一般情况 (二)特殊情况 三、this调用构造器 四、案例分析 (一)Account类 (二)Customer类 (三&…...
好写作AI:毕业论文“智造”新引擎,开启学术创作新纪元!
在学术探索的征途中,毕业论文无疑是一座巍峨的山峰,让无数莘莘学子既期待又忐忑。但别怕,时代在进步,科技在发展,我们有了新的“登山装备”——好写作AI。它不仅是你的学术助手,更是毕业论文“智造”的新引…...
IOFILE结构体的介绍与House of orange媚
认识Pass层级结构 Pass范围从上到下一共分为5个层级: 模块层级:单个.ll或.bc文件 调用图层级:函数调用的关系。 函数层级:单个函数。 基本块层级:单个代码块。例如C语言中{}括起来的最小代码。 指令层级:单…...
LangChain教程-、Langchain基础妨
简介 AI Agent 不仅仅是一个能聊天的机器人(如普通的 ChatGPT),而是一个能够感知环境、进行推理、自主决策并调用工具来完成特定任务的智能系统,更够完成更为复杂的AI场景需求。 AI Agent 功能 根据查阅的资料,agent的…...
快速上手Jimeng LoRA:Streamlit可视化界面,无需代码基础
快速上手Jimeng LoRA:Streamlit可视化界面,无需代码基础 你是否对AI绘画感兴趣,想尝试不同的艺术风格,却被复杂的命令行和代码部署劝退?你是否下载了多个不同训练阶段的LoRA模型,却苦于每次测试都要重新加…...
微信小程序反编译实战:用wxappUnpacker获取他人源码的完整流程(附常见报错解决方案)
微信小程序逆向工程全流程解析:从缓存提取到源码重构 最近两年微信小程序生态爆发式增长,各类创新应用层出不穷。作为开发者,我们常常会遇到一些令人惊艳的交互效果或功能实现,却苦于无法了解其背后的技术细节。本文将带你深入微信…...
Real-ESRGAN-GUI:终极AI图像增强工具,让模糊图片秒变高清
Real-ESRGAN-GUI:终极AI图像增强工具,让模糊图片秒变高清 【免费下载链接】Real-ESRGAN-GUI Lovely Real-ESRGAN / Real-CUGAN GUI Wrapper 项目地址: https://gitcode.com/gh_mirrors/re/Real-ESRGAN-GUI 在数字时代,我们每天都会接触…...
Windows与Office智能激活终极指南:KMS_VL_ALL_AIO全解析
Windows与Office智能激活终极指南:KMS_VL_ALL_AIO全解析 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为Windows和Office激活烦恼吗?KMS_VL_ALL_AIO是一款功能强大…...
SMTP认证失败?保姆级教程:如何正确配置163邮箱的POP3/SMTP服务
深度解析SMTP认证机制与163邮箱实战配置指南 引言:为什么你的邮件发送总是失败? 每次看到"535 Error: authentication failed"的报错信息,不少开发者都会陷入困惑——明明输入了正确的邮箱账号和密码,为什么系统还是拒绝…...
C++的std--span:非拥有式的连续内存视图
C的std::span:非拥有式的连续内存视图 在现代C编程中,高效且安全地处理连续内存数据是一项常见需求。传统方法通常依赖原始指针或迭代器,但这些方式容易引发越界访问或内存管理问题。C20引入的std::span为此提供了优雅的解决方案——它是一种…...
深入解析Android驱动开发:从HAL层到多媒体架构实战
第一章 Android驱动开发概述 Android驱动系统采用分层架构设计,主要包含以下层次: Linux内核层 → HAL层 → JNI层 → Framework层 → 应用层其中HAL(Hardware Abstraction Layer)作为硬件与框架的桥梁,通过标准接口实现硬件控制。典型HAL接口定义如下: // hardware/l…...
