Go Runtime功能初探


以下内容,是对 运行时 runtime的神奇用法 的学习与记录


目录:

  • 1.获取GOROOT环境变量
  • 2.获取GO的版本号
  • 3.获取本机CPU个数
  • 4.设置最大可同时执行的最大CPU数
  • 5.设置cup profile 记录的速录
  • 6.查看cup profile 下一次堆栈跟踪数据
  • 7.立即执行一次垃圾回收
  • 8.给变量绑定方法,当垃圾回收的时候进行监听
  • 9.查看内存申请和分配统计信息
  • 10.查看程序正在使用的字节数
  • 11.查看程序正在使用的对象数
  • 12.获取调用堆栈列表
  • 13.获取内存profile记录历史
  • 14.执行一个断点
  • 15.获取程序调用go协程的栈踪迹历史
  • 16.获取当前函数或者上层函数的标识号、文件名、调用方法在当前文件中的行号
  • 17.获取与当前堆栈记录相关链的调用栈踪迹
  • 18.获取一个标识调用栈标识符pc对应的调用栈
  • 19.获取调用栈所调用的函数的名字
  • 20.获取调用栈所调用的函数的所在的源文件名和行号
  • 21.获取该调用栈的调用栈标识符
  • 22.获取当前进程执行的cgo调用次数
  • 23.获取当前存在的go协程数
  • 24.终止掉当前的go协程
  • 25.让其他go协程优先执行,等其他协程执行完后,在执行当前的协程
  • 26.获取活跃的go协程的堆栈profile以及记录个数
  • 27.将调用的go协程绑定到当前所在的操作系统线程,其它go协程不能进入该线程
  • 28.解除go协程与操作系统线程的绑定关系
  • 29.获取线程创建profile中的记录个数
  • 30.控制阻塞profile记录go协程阻塞事件的采样率
  • 31.返回当前阻塞profile中的记录个数



1. GOROOT()获取GOROOT环境变量


GOROOT() 返回Go的根目录。如果存在GOROOT环境变量,返回该变量的值;否则,返回创建Go时的根目录

1
2
3
4
5
6
7
8
9
10
package main

import (
"fmt"
"runtime"
)

func main() {
fmt.Println(runtime.GOROOT()) // /Users/fliter/.g/go
}



2. Version() 获取GO的版本号


Version() 返回Go的版本字符串。要么是提交的hash和创建时的日期;要么是发行标签如”go1.20”

1
2
3
4
5
6
7
8
9
10
package main

import (
"fmt"
"runtime"
)

func main() {
fmt.Println(runtime.Version()) // go1.19
}



3. NumCPU() 获取本机CPU个数


NumCPU返回本地机器的逻辑CPU个数

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
"runtime"
)

func main() {
fmt.Println(runtime.NumCPU()) // 8

}




4. GOMAXPROCS() 设置最大可同时执行的最大CPU数


GOMAXPROCS() 设置可同时执行的最大CPU数,并返回先前的设置。 若 n < 1,则不会更改当前设置。

本地机器的逻辑CPU数可通过 NumCPU 查询。该函数在调度程序优化后会去掉?(啥时候..)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
"fmt"
"runtime"
"time"
)

func main() {

runtime.GOMAXPROCS(1)
startTime := time.Now()
var s1 chan int64 = make(chan int64)
var s2 chan int64 = make(chan int64)
var s3 chan int64 = make(chan int64)
var s4 chan int64 = make(chan int64)
go calc(s1)
go calc(s2)
go calc(s3)
go calc(s4)
<-s1
<-s2
<-s3
<-s4
endTime := time.Now()
fmt.Println(endTime.Sub(startTime)) // 第一行注释掉 耗时: 386.954625ms; 取消注释 耗时: 1.34715s

}
func calc(s chan int64) {
var count int64 = 0
for i := 0; i < 1000000000; i++ {
count += int64(i)
}
s <- count
}



5. SetCPUProfileRate() 设置cup profile 记录的速录


SetCPUProfileRate() 设置CPU profile记录的速率为平均每秒hz次。如果hz<=0,SetCPUProfileRate会关闭profile的记录。如果记录器在执行,该速率必须在关闭之后才能修改

绝大多数使用者应使用runtime/pprof包或testing包的-test.cpuprofile选项而非直接使用SetCPUProfileRate




6. CPUProfile 查看cup profile 下一次堆栈跟踪数据


func CPUProfile() []byte

已废弃




7. GC() 立即执行一次垃圾回收


Go三种触发GC的方式之一 (另外两种为2分钟固定一次 && 达到阈值时触发)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"runtime"
"time"
)

type Student struct {
name string
}

func main() {
var i *Student = new(Student)
runtime.SetFinalizer(i, func(i interface{}) {
println("垃圾回收了") // 垃圾回收了
})
runtime.GC() // 如果将这行注释,则上面不会输出
time.Sleep(time.Second)
}



8. SetFinalizer() 给变量绑定方法,当垃圾回收的时候进行监听


func SetFinalizer(x, f interface{})

注意x必须是指针类型,f 函数的参数一定要和x保持一致,或者写interface{},不然程序会报错

代码同上例




9. ReadMemStats() 查看内存申请和分配统计信息


可以获得如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
type MemStats struct {
// 一般统计
Alloc uint64 // 已申请且仍在使用的字节数
TotalAlloc uint64 // 已申请的总字节数(已释放的部分也算在内)
Sys uint64 // 从系统中获取的字节数(下面XxxSys之和)
Lookups uint64 // 指针查找的次数
Mallocs uint64 // 申请内存的次数
Frees uint64 // 释放内存的次数
// 主分配堆统计
HeapAlloc uint64 // 已申请且仍在使用的字节数
HeapSys uint64 // 从系统中获取的字节数
HeapIdle uint64 // 闲置span中的字节数
HeapInuse uint64 // 非闲置span中的字节数
HeapReleased uint64 // 释放到系统的字节数
HeapObjects uint64 // 已分配对象的总个数
// L低层次、大小固定的结构体分配器统计,Inuse为正在使用的字节数,Sys为从系统获取的字节数
StackInuse uint64 // 引导程序的堆栈
StackSys uint64
MSpanInuse uint64 // mspan结构体
MSpanSys uint64
MCacheInuse uint64 // mcache结构体
MCacheSys uint64
BuckHashSys uint64 // profile桶散列表
GCSys uint64 // GC元数据
OtherSys uint64 // 其他系统申请
// 垃圾收集器统计
NextGC uint64 // 会在HeapAlloc字段到达该值(字节数)时运行下次GC
LastGC uint64 // 上次运行的绝对时间(纳秒)
PauseTotalNs uint64
PauseNs [256]uint64 // 近期GC暂停时间的循环缓冲,最近一次在[(NumGC+255)%256]
NumGC uint32
EnableGC bool
DebugGC bool
// 每次申请的字节数的统计,61是C代码中的尺寸分级数
BySize [61]struct {
Size uint32
Mallocs uint64
Frees uint64
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
"fmt"
"runtime"
"time"
)

type Student2 struct {
name string
}

func main() {
var list = make([]*Student2, 0)
for i := 0; i < 100000; i++ {
var s *Student2 = new(Student2)
list = append(list, s)
}
memStatus := runtime.MemStats{}
runtime.ReadMemStats(&memStatus)
fmt.Printf("申请的内存:%d\n", memStatus.Mallocs) // 申请的内存:100250

fmt.Printf("释放的内存次数:%d\n", memStatus.Frees) // 释放的内存次数:45

time.Sleep(time.Second)
}



10. InUseBytes() 查看程序正在使用的字节数


func (r *MemProfileRecord) InUseBytes() int64

InUseBytes 返回正在使用的字节数(AllocBytes – FreeBytes)




11. InUseObjects() 查看程序正在使用的对象数


func (r *MemProfileRecord) InUseObjects() int64

InUseObjects 返回正在使用的对象数(AllocObjects - FreeObjects)




12. Stack() 获取调用堆栈列表


func (r *MemProfileRecord) Stack() []uintptr

Stack返回关联至此记录的调用栈踪迹,即r.Stack0的前缀




13. MemProfile() 获取内存profile记录历史


func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool)

MemProfile 返回当前内存profile中的记录数n

  • 若len(p)>=n,MemProfile会将此分析报告复制到p中并返回(n, true);

  • 若len(p)<n,MemProfile则不会更改p,而只返回(n, false)

如果inuseZero为true,该profile就会包含无效分配记录(其中r.AllocBytes>0,而r.AllocBytes==r.FreeBytes。这些内存都是被申请后又释放回运行时环境的)

大多数调用者应当使用runtime/pprof包或testing包的-test.memprofile标记,而非直接调用MemProfile




14. Breakpoint() 执行一个断点


runtime.Breakpoint()




15. Stack() 获取程序调用go协程的栈踪迹历史


func Stack(buf []byte, all bool) int

Stack 将调用其的go程的调用栈踪迹格式化后写入到buf中并返回写入的字节数

若all为true,函数会在写入当前go程的踪迹信息后,将其它所有go程的调用栈踪迹都格式化写入到buf中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"runtime"
"time"
)

func main() {
go showRecord()
time.Sleep(time.Second)
buf := make([]byte, 10000000000)
runtime.Stack(buf, true)
fmt.Println(string(buf))
}

func showRecord() {
ticker := time.Tick(time.Second)
for t := range ticker {
fmt.Println(t)
}
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2023-04-19 17:25:26.386522 +0800 CST m=+1.001105543
2023-04-19 17:25:27.386892 +0800 CST m=+2.001489376
2023-04-19 17:25:28.386505 +0800 CST m=+3.001116043
2023-04-19 17:25:29.38553 +0800 CST m=+4.000154334
2023-04-19 17:25:30.385618 +0800 CST m=+5.000255584
2023-04-19 17:25:31.385817 +0800 CST m=+6.000468334
2023-04-19 17:25:32.385528 +0800 CST m=+7.000192918
2023-04-19 17:25:33.385646 +0800 CST m=+8.000323543
goroutine 1 [running]:
main.main()
/Users/fliter/runtime-demo/15Stack.go:13 +0x68

goroutine 4 [chan receive]:
main.showRecord()
/Users/fliter/runtime-demo/15Stack.go:19 +0xac
created by main.main
/Users/fliter/runtime-demo/15Stack.go:10 +0x24



16. Caller() 获取当前函数或者上层函数的标识号、文件名、调用方法在当前文件中的行号


func Caller(skip int) (pc uintptr, file string, line int, ok bool)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
"runtime"
)

func main() {
pc, file, line, ok := runtime.Caller(0)
fmt.Println(pc) // 4336410771
fmt.Println(file) // /Users/fliter/runtime-demo/16Caller.go
fmt.Println(line) //9
fmt.Println(ok) //true
}

pc = 4336410771 不是main函数的标识,而是runtime.Caller 方法的标识,line = 13 标识它在main方法中的第13行被调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//package main
//
//import (
// "fmt"
// "runtime"
//)
//
//func main() {
// pc, file, line, ok := runtime.Caller(0)
// fmt.Println(pc) // 4336410771
// fmt.Println(file) // /Users/fliter/runtime-demo/16Caller.go
// fmt.Println(line) //9
// fmt.Println(ok) //true
//}

package main

import (
"fmt"
"runtime"
)

func main() {
pc, _, line, _ := runtime.Caller(1)
fmt.Printf("main函数的pc:%d\n", pc) // main函数的pc:4364609931
fmt.Printf("main函数被调用的行数:%d\n", line) // main函数被调用的行数:250
show()
}
func show() {
pc, _, line, _ := runtime.Caller(1)
fmt.Printf("show函数的pc:%d\n", pc) // show函数的pc:4364974271
fmt.Printf("show函数被调用的行数:%d\n", line) // show函数被调用的行数:27
// 这个是main函数的栈
pc, _, line, _ = runtime.Caller(2)
fmt.Printf("show的上层函数的pc:%d\n", pc) // show的上层函数的pc:4364609931
fmt.Printf("show的上层函数被调用的行数:%d\n", line) // show的上层函数被调用的行数:250
pc, _, _, _ = runtime.Caller(3)
fmt.Println(pc) //4364778899
pc, _, _, _ = runtime.Caller(4)
fmt.Println(pc) // 0
}


golang获取调用者的方法名及所在行数

runtime.Caller的性能问题




17. Callers() 获取与当前堆栈记录相关链的调用栈踪迹


func Callers(skip int, pc []uintptr) int

会把当前go程调用栈上的调用栈标识符填入切片pc中,返回写入到pc中的项数。实参skip为开始在pc中记录之前所要跳过的栈帧数,0表示Callers自身的调用栈,1表示Callers所在的调用栈。返回写入p的项数

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"
"runtime"
)

func main() {
pcs := make([]uintptr, 10)
i := runtime.Callers(1, pcs)
fmt.Println(pcs[:i]) // [4311883569 4311525404 4311694372]
}

获得了三个pc 其中有一个是main方法自身的




18. FuncForPC() 获取一个标识调用栈标识符pc对应的调用栈


func FuncForPC(pc uintptr) *Func

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"runtime"
)

func main() {

pcs := make([]uintptr, 10)
i := runtime.Callers(1, pcs)
for _, pc := range pcs[:i] {
println(runtime.FuncForPC(pc))
}
}

输出:

1
2
3
0x102f660f0
0x102f5c9f0
0x102f64840

用途见下




19. Name() 获取调用栈所调用的函数的名字


func (f *Func) string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"runtime"
)

func main() {

pcs := make([]uintptr, 10)
i := runtime.Callers(1, pcs)
for _, pc := range pcs[:i] {
funcPC := runtime.FuncForPC(pc)
println(funcPC.Name())
}
}

输出:

1
2
3
main.main
runtime.main
runtime.goexit



20. FileLine() 获取调用栈所调用的函数的所在的源文件名和行号


func (f *Func) FileLine(pc uintptr) (file string, line int)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"runtime"
)

func main() {
pcs := make([]uintptr, 10)
i := runtime.Callers(1, pcs)
for _, pc := range pcs[:i] {
funcPC := runtime.FuncForPC(pc)
file, line := funcPC.FileLine(pc)
println(funcPC.Name(), file, line)
}
}

输出:

1
2
3
main.main /Users/fliter/runtime-demo/20FileLine.go 9
runtime.main /Users/fliter/.g/go/src/runtime/proc.go 259
runtime.goexit /Users/fliter/.g/go/src/runtime/asm_arm64.s 1166



21. Entry() 获取该调用栈的调用栈标识符


func (f *Func) Entry() uintptr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"runtime"
)

func main() {
pcs := make([]uintptr, 10)
i := runtime.Callers(1, pcs)
for _, pc := range pcs[:i] {
funcPC := runtime.FuncForPC(pc)
println(funcPC.Entry())
}
}

输出:

1
2
3
4310699120
4310540672
4310690704



22. NumCgoCall() 获取当前进程执行的cgo调用次数


获取当前进程调用C方法的次数

func NumCgoCall() int64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"runtime"
)

/*
#include <stdio.h>
*/
import "C"

func main() {
println(runtime.NumCgoCall()) // 1
}

没有调用C的方法为什么是1呢?因为 import C 会调用C包中的init方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"runtime"
)

/*
#include <stdio.h>
// 自定义一个c语言的方法
static void myPrint(const char* msg) {
printf("myPrint: %s", msg);
}
*/
import "C"

func main() {
// 调用c方法
C.myPrint(C.CString("Hello,C\n")) // myPrint: Hello,C
println(runtime.NumCgoCall()) // 3
}



23. NumGoroutine() 获取当前存在的go协程数


func NumGoroutine() int

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "runtime"

func main() {
go print()
print()
println(runtime.NumGoroutine()) // 2
}
func print() {

}

当前程序有 2个go协程 一个是main.go主协程, 另外一个是 go print()




24. Goexit() 终止掉当前的go协程


func Goexit()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
"runtime"
)

func main() {
print()
fmt.Println("继续执行")
}
func print() {
fmt.Println("准备结束go协程")
runtime.Goexit()
defer fmt.Println("结束了")
}

输出:

1
2
3
准备结束go协程
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
exit status 2

Goexit终止调用它的go协程,其他协程不受影响,Goexit会在终止该go协程前执行所有的defer函数,前提是defer必须在它前面定义,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"runtime"
)

func main() {
print()
fmt.Println("继续执行")
}
func print() {
fmt.Println("准备结束go协程")
defer fmt.Println("结束了--会输出出来")
runtime.Goexit()
//defer fmt.Println("结束了")
}

输出:

1
2
3
4
准备结束go协程
结束了--会输出出来
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
exit status 2

如果在 main主协程调用该方法,会终止 主协程,但不会让main返回,因为main函数没有返回,

程序会继续执行其他go协程,当其他go协程执行完毕后,程序就会崩溃

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"runtime"
"time"
)

func main() {

start := time.Now()
go func() {
time.Sleep(3e9)
println("123")
}()

defer fmt.Println(time.Since(start))
runtime.Goexit()

}

输出:

1
2
3
4
20.5µs
123
fatal error: no goroutines (main called runtime.Goexit) - deadlock!
exit status 2



25. Gosched() 让其他go协程优先执行,等其他协程执行完后,再执行当前的协程


func Gosched()

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import (
"fmt"
)

func main() {
go print25()
fmt.Println("继续执行")
}
func print25() {
fmt.Println("执行打印方法")
}

调用了go print方法,但是还未执行, main函数就执行完毕了(启一个协程也是需要时间的,这个时间比for循环,比程序继续执行要耗时多很多)

可以使用channel,waitgroup等,此处使用 runtime.Gosched()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
"runtime"
)

func main() {
go print25()
runtime.Gosched()
fmt.Println("继续执行")
}
func print25() {
fmt.Println("执行打印方法")
}

输出:

1
2
执行打印方法
继续执行

Rust vs Go:常用语法对比(13)-将优先权让给其他线程

Go用两个协程交替打印100以内的奇偶数




26. GoroutineProfile() 获取活跃的go协程的堆栈profile以及记录个数


func GoroutineProfile(p []StackRecord) (n int, ok bool)

1
2
3
4
5
6
7
8
9
10
// GoroutineProfile returns n, the number of records in the active goroutine stack profile.
// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
// If len(p) < n, GoroutineProfile does not change p and returns n, false.
//
// Most clients should use the runtime/pprof package instead
// of calling GoroutineProfile directly.
func GoroutineProfile(p []StackRecord) (n int, ok bool) {

return goroutineProfileWithLabels(p, nil)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"runtime"
)

func main() {

for i := 0; i < 10; i++ {

go func(k int) {
fmt.Println(i)
}(i)
}

fmt.Println("----------------")
p := make([]runtime.StackRecord, 10000)

fmt.Println(runtime.GoroutineProfile(p)) // 1 true
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
10
10
10
10
10
10
10
----------------
7
10
10
1 true

pprof里面使用了此func

Go 应用的性能优化




27. LockOSThread() 将调用的go协程绑定到当前所在的操作系统线程,其它go协程不能进入该线程


func LockOSThread()

将调用的go程绑定到它当前所在的操作系统线程。除非调用的go程退出或调用UnlockOSThread,否则它将总是在该线程中执行,而其它go程不能进入该线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
"fmt"
"runtime"
"time"
)

func main() {
go calcSum1()
go calcSum2()
time.Sleep(time.Second * 10)
}

func calcSum1() {
runtime.LockOSThread()
start := time.Now()
count := 0
for i := 0; i < 10000000000; i++ {
count += i
}
end := time.Now()
fmt.Println("calcSum1耗时")
fmt.Println(end.Sub(start))
defer runtime.UnlockOSThread()
}

func calcSum2() {
start := time.Now()
count := 0
for i := 0; i < 10000000000; i++ {
count += i
}
end := time.Now()
fmt.Println("calcSum2耗时")
fmt.Println(end.Sub(start))
}

输出:

1
2
3
4
calcSum1耗时
3.295679583s
calcSum2耗时
3.296763125s

看起来没有太大的差别;

但估计在很多个协程(涉及到频繁的调度和切换),但是有一项重要功能需独占一个核,可使用该func


Go LockOSThread




28. UnlockOSThread() 解除go协程与操作系统线程的绑定关系


func UnlockOSThread()

将调用此func的协程,解除和其绑定的操作系统线程

若调用的协程未调用LockOSThread,UnlockOSThread不做操作

从1,10之后,调用了多少次LockOSThread,就要使用UnlockOSThread接触绑定..




29. ThreadCreateProfile() 获取线程创建profile中的记录个数


func ThreadCreateProfile(p []StackRecord) (n int, ok bool)

返回线程创建profile中的记录个数。

  • 如果len(p)>=n,本func就会将profile中的记录复制到p中并返回(n, true)
  • 若len(p)<n,则不会更改p,而只返回(n, false)

绝大多数情况下应当使用runtime/pprof包,而非直接调用ThreadCreateProfile




30. SetBlockProfileRate() 控制阻塞profile记录go协程阻塞事件的采样率


func SetBlockProfileRate(rate int)

SetBlockProfileRate 控制阻塞profile记录go程阻塞事件的采样频率。对于一个阻塞事件,平均每阻塞rate纳秒,阻塞profile记录器就采集一份样本。

  • 要在profile中包括每一个阻塞事件,需传入rate=1
  • 要完全关闭阻塞profile的记录,需传入rate<=0



31. BlockProfile() 返回当前阻塞profile中的记录个数


func BlockProfile(p []BlockProfileRecord) (n int, ok bool)

BlockProfile返回当前阻塞profile中的记录个数

  • 如果len(p)>=n,本函数就会将此profile中的记录复制到p中并返回(n, true)

  • 如果len(p)<n,本函数则不会修改p,而只返回(n, false)

绝大多数情况应当使用runtime/pprof包或testing包的-test.blockprofile标记, 而非直接调用 BlockProfile




文章目录

  1. 1. GOROOT()获取GOROOT环境变量
  2. 2. Version() 获取GO的版本号
  3. 3. NumCPU() 获取本机CPU个数
  4. 4. GOMAXPROCS() 设置最大可同时执行的最大CPU数
  5. 5. SetCPUProfileRate() 设置cup profile 记录的速录
  6. 6. CPUProfile 查看cup profile 下一次堆栈跟踪数据
  7. 7. GC() 立即执行一次垃圾回收
  8. 8. SetFinalizer() 给变量绑定方法,当垃圾回收的时候进行监听
  9. 9. ReadMemStats() 查看内存申请和分配统计信息
  10. 10. InUseBytes() 查看程序正在使用的字节数
  11. 11. InUseObjects() 查看程序正在使用的对象数
  12. 12. Stack() 获取调用堆栈列表
  13. 13. MemProfile() 获取内存profile记录历史
  14. 14. Breakpoint() 执行一个断点
  15. 15. Stack() 获取程序调用go协程的栈踪迹历史
  16. 16. Caller() 获取当前函数或者上层函数的标识号、文件名、调用方法在当前文件中的行号
  17. 17. Callers() 获取与当前堆栈记录相关链的调用栈踪迹
  18. 18. FuncForPC() 获取一个标识调用栈标识符pc对应的调用栈
  19. 19. Name() 获取调用栈所调用的函数的名字
  20. 20. FileLine() 获取调用栈所调用的函数的所在的源文件名和行号
  21. 21. Entry() 获取该调用栈的调用栈标识符
  22. 22. NumCgoCall() 获取当前进程执行的cgo调用次数
  23. 23. NumGoroutine() 获取当前存在的go协程数
  24. 24. Goexit() 终止掉当前的go协程
  25. 25. Gosched() 让其他go协程优先执行,等其他协程执行完后,再执行当前的协程
  26. 26. GoroutineProfile() 获取活跃的go协程的堆栈profile以及记录个数
  27. 27. LockOSThread() 将调用的go协程绑定到当前所在的操作系统线程,其它go协程不能进入该线程
  28. 28. UnlockOSThread() 解除go协程与操作系统线程的绑定关系
  29. 29. ThreadCreateProfile() 获取线程创建profile中的记录个数
  30. 30. SetBlockProfileRate() 控制阻塞profile记录go协程阻塞事件的采样率
  31. 31. BlockProfile() 返回当前阻塞profile中的记录个数