Skip to content
gqlxj1987's Blog
Go back

golang 机制了解

Edit page

原文链接

go语言初始化过程

这里解释一下本地线程存储。比如说每个goroutine都有自己的控制信息,这些信息是存放在一个结构体G中。假设我们有一个全局变量g是结构体G的指针,我们希望只有唯一的全局变量g,而不是g0,g1,g2…但是我们又希望不同goroutine去访问这个全局变量g得到的并不是同一个东西,它们得到的是相对自己线程的结构体G,这种情况下就需要本地线程存储。g确实是一个全局变量,却在不同线程有多份不同的副本。每个goroutine去访问g时,都是对应到自己线程的这一份副本。针对goroutine部分,

  CLD                // convention is D is always left cleared
  CALL    runtime·check(SB) //检测像int8,int16,float等是否是预期的大小,检测cas操作是否正常
  MOVL    16(SP), AX        // copy argc
  MOVL    AX, 0(SP)
  MOVQ    24(SP), AX        // copy argv
  MOVQ    AX, 8(SP)
  CALL    runtime·args(SB)    //将argc,argv设置到static全局变量中了
  CALL    runtime·osinit(SB)    //osinit做的事情就是设置runtime.ncpu,不同平台实现方式不一样
  CALL    runtime·hashinit(SB)    //使用读/dev/urandom的方式从内核获得随机数种子
  CALL    runtime·schedinit(SB)    //内存管理初始化,根据GOMAXPROCS设置使用的procs等等

go关键字的调用协议:先将参数进栈,再被调函数指针和参数字节数进栈,接着调用runtime.newproc函数。所以这里其实就是新开个goroutine执行runtime.main

找到一个等待运行的g
如果g是锁定到某个M的,则让那个M运行
否则,调用execute函数让g在当前的M中运行

goroutine状态图

func M() {
    for {
        sched.lock.Lock()    //互斥地从就绪G队列中取一个g出来运行
        if sched.allg > 0 {
            g := sched.allg[0]
            sched.allg = sched.allg[1:]
            sched.lock.Unlock()
            g.Run()        //运行它
        } else {
            sched.lock.Unlock()
        }
    }
}

退出goroutine

func exitsyscall() {
    if len(allm) >= GOMAXPROCS {
        sched.lock.Lock()
        sched.allg = append(sched.allg, g)    //把g放回到队列中
        sched.lock.Unlock()
        time.Sleep()    //这个M不再干活
    }
}

内存管理

在多线程方面,很自然的做法就是每条线程都有自己的本地的内存,然后有一个全局的分配链,当某个线程中内存不足后就向全局分配链中申请内存。这样就避免了多线程同时访问共享变量时的加锁。 在避免内存碎片方面,大块内存直接按页为单位分配,小块内存会切成各种不同的固定大小的块,申请做任意字节内存时会向上取整到最接近的块,将整块分配给申请者以避免随意切割。

分配器的数据结构包括:

我们可以将Go语言的内存管理看成一个两级的内存管理结构,MHeap和MCache。

非阻塞io

底层非阻塞io是如何实现的呢?简单地说,所有文件描述符都被设置成非阻塞的,某个goroutine进行io操作,读或者写文件描述符,如果此刻io还没准备好,则这个goroutine会被放到系统的等待队列中,这个goroutine失去了运行权,但并不是真正的整个系统“阻塞”于系统调用。

后台还有一个poller会不停地进行poll,所有的文件描述符都被添加到了这个poller中的,当某个时刻一个文件描述符准备好了,poller就会唤醒之前因它而阻塞的goroutine,于是goroutine重新运行起来


Edit page
Share this post on:

Previous Post
golang race
Next Post
Dynamic Programming