golang八股文
Golang goroutine内存泄漏 slice导致 获取长字符串中的一段,导致字符串未释放; 获取长slice中的一段导致长slice未释放; 在长切片中新建sllice导致泄漏 channel导致 发送不接受,接收不发送,nil channel 从 channel 里读,但是同时没有写入操作 向 无缓冲 channel 里写,但是同时没有读操作 向已满的 有缓冲 channel 里写,但是同时没有读操作 select操作在所有case上都阻塞() goroutine进入死循环,一直结束不了 向 nil channel 发送和接收数据都将会导致阻塞。这种情况可能在我们定义 channel 时忘记初始化的时候发生。 可见,很多都是因为channel使用不当造成阻塞,从而导致goroutine也一直阻塞无法退出导致的。 传统同步方式sync.mutex,sync.waitgroup导致 用了mutex加lock之后忘记unlock; 在一开始设置了具体数目的wg.wait(n),但是有没有写够足够数量n的wg.Done(),导致wg.Wait()一直等待下去。(正确方式可以使用wg.Add(1)配合wg.Done使用) Go调度器的GMP 在Go语言中,GPM通常指的是Goroutine、Processor和Machine,这是Go调度器(scheduler)的核心组成部分。下面是对每个部分的详细介绍: Goroutine (G): Goroutine是Go语言中的轻量级线程,由Go运行时管理。它们是并发的基本单位,可以被创建和销毁,而无需操作系统级别的线程开销。Goroutine的创建和销毁非常快速,因此可以轻松地创建成千上万个Goroutine。 Goroutine的调度是协作式的,这意味着一个Goroutine在执行时会自愿放弃CPU,让其他Goroutine有机会执行。这种协作式调度使得Go语言能够高效地利用多核处理器。 Processor (P): Processor是Go调度器中的一个抽象概念,代表一个逻辑处理器。每个P都有一个本地运行队列,用于存储待执行的Goroutine。P的数量可以通过环境变量或运行时设置来调整,通常设置为CPU的核心数。 P的主要作用是管理Goroutine的执行。当一个Goroutine被调度到P上时,P会将其分配给一个可用的Machine(M)来执行。 Machine (M): Machine代表一个操作系统线程。M与P关联,负责执行Goroutine。一个M可以与多个P关联,但在任何给定时间,一个M只能执行一个P的Goroutine。 M的主要作用是执行Goroutine的代码。当一个Goroutine被调度到M上时,M会执行该Goroutine的代码,直到该Goroutine自愿放弃CPU或被抢占。 Go调度器的工作原理是将Goroutine(G)分配到Processor(P)上,然后由Machine(M)执行。这种设计使得Go语言能够高效地利用多核处理器,并实现高并发。 在 Go 语言的运行时系统中,Goroutine(简称 G)有多种状态,用于描述它在不同时间点的执行情况。这些状态在 Go 的调度器(GMP 模型)中扮演重要角色。GMP 模型由 Goroutine(G)、工作线程(M)和处理器(P)三部分组成。以下是 G 的主要状态及其转变过程,以及它们与 GMP 模型的关系。 G 的状态 _Gidle:空闲状态。Goroutine 尚未被使用或已经完成执行,等待被分配新任务。 _Grunnable:可运行状态。Goroutine 已经准备好运行,等待被调度器选中运行。 _Grunning:运行状态。Goroutine 正在运行中。 _Gsyscall:系统调用状态。Goroutine 正在执行系统调用,处于阻塞状态,不会被调度器调度。 _Gwaiting:等待状态。Goroutine 在等待某个条件(例如通道操作、定时器、网络 I/O 等)完成。 _Gdead:死亡状态。Goroutine 已经完成执行,无法再被重新使用。 _Gcopystack:堆栈复制状态。Goroutine 的堆栈正在被复制,以调整其大小。 状态转变及其与 GMP 的关系 创建 Goroutine _Gidle -> _Grunnable 创建一个新的 Goroutine,并将其状态设置为 _Grunnable,表示该 Goroutine 准备好运行。 由 P 将新的 Goroutine 添加到其本地运行队列或全局运行队列中。 g := newGoroutine() g....