GO语言中的runtime功能概要

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
函数计算FC,每月15万CU 3个月
应用实时监控服务-应用监控,每月50GB免费额度
简介: 【5月更文挑战第17天】本文简介Go语言的`runtime`库支撑着高效的并发和内存管理。此外,runtime还涉及定时器、错误处理(Panic和Recover)以及反射功能。通过内联展开和逃逸分析等手段,实现性能优化。

1 runtime机制

Go语言的runtime库提供了一系列底层功能,支持高效的并发执行和内存管理。其中Goroutines是轻量级线程,具有小栈和自动调整大小的特性,通过MPG调度模型在多个线程上运行。

内存管理涉及堆栈分配和逃逸分析,垃圾回收采用并发标记-清除算法,分代收集优化效率。Channels提供同步机制,Select进行多路复用。

以下是对Go语言runtime库中两个关键功能——Goroutines和GC垃圾回收机制的深入解析。

2. Goroutines

  • Goroutine简介

Goroutine是Go语言的一种轻量级线程,支持大规模并发执行。Goroutine的创建和调度开销远小于传统操作系统线程。

  • Goroutine的实现

初始栈大小:每个Goroutine的初始栈大小约为2KB,且会根据需要自动增长和收缩。

调度模型:Go采用MPG调度模型,即多个Goroutine映射到多个操作系统线程上。

调度器(Scheduler)结构:

G:代表一个Goroutine,包含Goroutine的栈和程序计数器等信息。
M:代表一个操作系统线程,用于执行Goroutine。
P:代表逻辑处理器,管理Goroutine队列。

调度器的主要任务是将G分配给M执行,P的数量可以通过GOMAXPROCS环境变量设置。

从图表上讲,我们可以将调度程序表示为:

        M
        |
        P -- G
        |    |
        G    G
             |
             G

在单核情况下,所有 Goroutine运行在同一个线程, M0中,每一个线程维护一个上下文 Content, P任何时刻,一个上下文只有一个 Goroutine,其他Goroutine在运行时 队列queue等待。

一个Goroutine 运行完成自己的时间片后,让出上下文,自己回到运行队列

当正在运行的GO阻塞时,可以IO,将再创建一个线程 M1,P转到新的线程中运行

        M0           M1             syscall
        |            |                MQ
        P  —— G      P - G             |
        |     |          |             Go
        Go    G          G
              |          |
              G          G

当M0 返回时,它会尝试从其他线程中 偷一个上下文,

如果没有获取到,将把 Goroutine 放到 Global 运行队列中。
然后把自己放入线程缓冲。

3 内存管理

  • 内存分配

堆和栈:Go程序中的变量可以分配在栈或堆上。栈上分配的变量在函数返回时自动释放,堆上分配的变量需要通过垃圾回收器回收。

逃逸分析:编译器在编译时进行逃逸分析,确定变量是否需要分配到堆上。逃逸到堆上的变量生命周期更长,但会增加GC负担。

4 垃圾回收(GC)

  • 并发标记-清除算法

三色标记法:对象分为白色(未访问)、灰色(已访问但未处理完)、黑色(已处理完)。

GC线程从根对象开始标记,将对象从白色变为灰色,再变为黑色。

写屏障(Write Barrier):在标记阶段,写屏障确保新创建或引用的对象被正确标记,以维持标记的准确性。

  • GC阶段

标记开始(Mark Start):暂停所有Goroutine,标记根对象。
并发标记(Concurrent Marking):并发标记对象,允许程序继续执行。
标记终止(Mark Termination):再次暂停所有Goroutine,完成标记过程。
清除阶段(Sweep):回收未标记的对象内存。

  • 分代收集
    分代思想:虽然Go主要采用并发标记-清除算法,但引入了分代思想,优先回收生命周期较短的对象,提高GC效率。

    Go根据对象大小 将对象分为3类

  • 微小对象 Tiny size <16B

    使用mcache的微小分配器分配大小小于 16个字节的对象,在单个16字节块上可以完成多个微小分配

  • 小对象 16B ~32KB

大小在16个字节和32k字节之间的对象被分配在G运行所在的P ncache对应 mspan size class

在微小型和小型 对象种秒如果mspan列表为空,分配器将从 mheap获取大量页面用于mspan

如果mheap为空或 没有足够大的页面满足分配请求,那么它将从操作系统分配一组新的页 至少 1MB

  • 大对象

大小 >32KB, 大于 32KB 的对象直接分配在 mheap的相应大小类上 size class

如果 mheap为空或 没有足够大的页面满足分配请求,则它将从操作系统分配一组新的页 至少 1MB

如果遇到内存不足的问题 out of memory,不当的内存管理也可能导致内存泄露

GC内存管理堆内存,简单说,它释放了孤儿对象 orphan object 使用的内存,所谓孤儿对象是指那些不再被栈 直接或间接引用的对象。

从GO1.12版本开始,Go使用非分代,并发的,基于三色标记和清理的垃圾回收器。

5. 并发原语

  • Channels

同步机制:Channels用于Goroutine之间的通信和同步,通过make函数创建。可以指定缓冲区大小,支持无缓冲和有缓冲两种模式。

操作:chan <- value发送数据,<- chan接收数据。支持select语句进行多路复用。

  • Select语句

多路复用:select语句允许在多个channel操作中进行选择,第一个准备好的操作会被执行,常用于处理多路通信。

6. 其他runtime功能

  • 定时器

time包:提供定时器功能,通过time.NewTimer和time.NewTicker创建定时器,定时器触发时向channel发送信号。

  • Panic和Recover

错误处理:panic用于引发异常,recover用于捕获异常,防止程序崩溃。
反射(Reflection)
反射机制:通过reflect包提供反射能力,允许在运行时检查和操作对象的类型和值。

7. 性能优化

  • runtime可以用于编译器优化

内联展开:编译器将小函数内联到调用处,减少函数调用开销。

逃逸分析:编译器分析变量的作用域,决定变量是分配在栈上还是堆上。

目录
相关文章
|
3天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
14 2
|
5天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
79 58
|
4天前
|
监控 Go API
Go语言在微服务架构中的应用实践
在微服务架构的浪潮中,Go语言以其简洁、高效和并发处理能力脱颖而出,成为构建微服务的理想选择。本文将探讨Go语言在微服务架构中的应用实践,包括Go语言的特性如何适应微服务架构的需求,以及在实际开发中如何利用Go语言的特性来提高服务的性能和可维护性。我们将通过一个具体的案例分析,展示Go语言在微服务开发中的优势,并讨论在实际应用中可能遇到的挑战和解决方案。
|
1天前
|
Go
go语言中的 跳转语句
【11月更文挑战第4天】
7 4
|
1天前
|
JSON 安全 Go
Go语言中使用JWT鉴权、Token刷新完整示例,拿去直接用!
本文介绍了如何在 Go 语言中使用 Gin 框架实现 JWT 用户认证和安全保护。JWT(JSON Web Token)是一种轻量、高效的认证与授权解决方案,特别适合微服务架构。文章详细讲解了 JWT 的基本概念、结构以及如何在 Gin 中生成、解析和刷新 JWT。通过示例代码,展示了如何在实际项目中应用 JWT,确保用户身份验证和数据安全。完整代码可在 GitHub 仓库中查看。
10 1
|
1天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
8 2
|
1天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
9 2
|
5天前
|
Go 数据处理 API
Go语言在微服务架构中的应用与优势
本文摘要采用问答形式,以期提供更直接的信息获取方式。 Q1: 为什么选择Go语言进行微服务开发? A1: Go语言的并发模型、简洁的语法和高效的编译速度使其成为微服务架构的理想选择。 Q2: Go语言在微服务架构中有哪些优势? A2: 主要优势包括高性能、高并发处理能力、简洁的代码和强大的标准库。 Q3: 文章将如何展示Go语言在微服务中的应用? A3: 通过对比其他语言和展示Go语言在实际项目中的应用案例,来说明其在微服务架构中的优势。
|
5天前
|
Go 数据处理 调度
探索Go语言的并发模型:Goroutines与Channels的协同工作
在现代编程语言中,Go语言以其独特的并发模型脱颖而出。本文将深入探讨Go语言中的Goroutines和Channels,这两种机制如何协同工作以实现高效的并发处理。我们将通过实际代码示例,展示如何在Go程序中创建和管理Goroutines,以及如何使用Channels进行Goroutines之间的通信。此外,本文还将讨论在使用这些并发工具时可能遇到的常见问题及其解决方案,旨在为Go语言开发者提供一个全面的并发编程指南。
|
3天前
|
Go 调度 开发者
探索Go语言中的并发模式:goroutine与channel
在本文中,我们将深入探讨Go语言中的核心并发特性——goroutine和channel。不同于传统的并发模型,Go语言的并发机制以其简洁性和高效性著称。本文将通过实际代码示例,展示如何利用goroutine实现轻量级的并发执行,以及如何通过channel安全地在goroutine之间传递数据。摘要部分将概述这些概念,并提示读者本文将提供哪些具体的技术洞见。