01.三色标记法原理
a.基本概念
三色标记法是Go GC使用的核心算法,将对象分为白色(未标记)、灰色(已标记但未扫描)、黑色(已标记已扫描)三种状态。
b.标记过程
a.初始状态
所有对象为白色,根对象标记为灰色。
b.标记阶段
从灰色对象开始,扫描其引用的对象,将引用对象标记为灰色,自身标记为黑色。
c.清除阶段
标记完成后,白色对象即为垃圾,可以回收。
c.代码示例
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
"time"
)
type Node struct {
data int
next *Node
large []byte
}
func createLinkedList(n int) *Node {
head := &Node{data: 0, large: make([]byte, 1024)}
current := head
for i := 1; i < n; i++ {
current.next = &Node{data: i, large: make([]byte, 1024)}
current = current.next
}
return head
}
func main() {
var m runtime.MemStats
// 创建对象图
fmt.Println("创建1000个节点的链表...")
head := createLinkedList(1000)
runtime.ReadMemStats(&m)
fmt.Printf("创建后: HeapAlloc=%d KB, HeapObjects=%d\n",
m.HeapAlloc/1024, m.HeapObjects)
// 断开一半节点的引用
current := head
for i := 0; i < 500; i++ {
current = current.next
}
current.next = nil // 后500个节点变为垃圾
fmt.Println("\n断开后500个节点的引用...")
// 触发GC,观察三色标记
fmt.Println("触发GC...")
start := time.Now()
runtime.GC()
duration := time.Since(start)
runtime.ReadMemStats(&m)
fmt.Printf("GC后: HeapAlloc=%d KB, HeapObjects=%d\n",
m.HeapAlloc/1024, m.HeapObjects)
fmt.Printf("GC耗时: %v\n", duration)
fmt.Printf("GC次数: %d\n", m.NumGC)
_ = head
}
---
02.并发标记
a.并发标记的优势
Go的GC是并发的,标记阶段与用户程序并发执行,减少STW(Stop The World)时间。
b.标记流程
a.STW阶段1
准备GC,启动写屏障,扫描栈和全局变量。
b.并发标记
与用户程序并发执行,标记堆上对象。
c.STW阶段2
完成标记,关闭写屏障,清理工作。
c.代码示例
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
"sync"
"time"
)
func allocateWorker(id int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 100; i++ {
// 持续分配内存,与GC并发
data := make([]byte, 10*1024) // 10KB
_ = data
time.Sleep(10 * time.Millisecond)
}
}
func main() {
// 设置GC参数
debug.SetGCPercent(50) // 降低GC阈值,更频繁触发
var m runtime.MemStats
var wg sync.WaitGroup
fmt.Println("启动10个并发worker...")
for i := 0; i < 10; i++ {
wg.Add(1)
go allocateWorker(i, &wg)
}
// 监控GC
go func() {
lastGC := uint32(0)
for {
runtime.ReadMemStats(&m)
if m.NumGC > lastGC {
fmt.Printf("[GC #%d] PauseNs=%v, HeapAlloc=%d KB\n",
m.NumGC,
time.Duration(m.PauseNs[(m.NumGC+255)%256]),
m.HeapAlloc/1024)
lastGC = m.NumGC
}
time.Sleep(100 * time.Millisecond)
}
}()
wg.Wait()
time.Sleep(500 * time.Millisecond)
runtime.ReadMemStats(&m)
fmt.Printf("\n总GC次数: %d\n", m.NumGC)
fmt.Printf("总GC暂停时间: %v\n", time.Duration(m.PauseTotalNs))
fmt.Printf("平均GC暂停: %v\n", time.Duration(m.PauseTotalNs)/time.Duration(m.NumGC))
}
---
03.增量标记与混合写屏障
a.增量标记
将标记工作分散到多个小步骤中,每次只标记一部分对象,减少单次暂停时间。
b.混合写屏障
a.功能说明
Go 1.8引入混合写屏障,结合了插入写屏障和删除写屏障的优点,减少STW时间。
b.工作原理
在标记阶段,当指针被修改时,写屏障确保新旧对象都被正确标记。
c.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
type Object struct {
id int
ref *Object
data []byte
}
func main() {
var m runtime.MemStats
var wg sync.WaitGroup
// 创建对象图
objects := make([]*Object, 1000)
for i := range objects {
objects[i] = &Object{
id: i,
data: make([]byte, 1024),
}
}
// 建立引用关系
for i := 0; i < len(objects)-1; i++ {
objects[i].ref = objects[i+1]
}
fmt.Println("初始对象图创建完成")
runtime.ReadMemStats(&m)
fmt.Printf("HeapObjects: %d\n", m.HeapObjects)
// 并发修改引用(触发写屏障)
wg.Add(10)
for i := 0; i < 10; i++ {
go func(id int) {
defer wg.Done()
for j := 0; j < 100; j++ {
idx := (id*100 + j) % len(objects)
newIdx := (idx + 1) % len(objects)
objects[idx].ref = objects[newIdx] // 触发写屏障
time.Sleep(1 * time.Millisecond)
}
}(i)
}
// 同时触发GC
go func() {
time.Sleep(50 * time.Millisecond)
fmt.Println("\n触发GC...")
runtime.GC()
fmt.Println("GC完成")
}()
wg.Wait()
runtime.ReadMemStats(&m)
fmt.Printf("\n最终HeapObjects: %d\n", m.HeapObjects)
fmt.Printf("GC次数: %d\n", m.NumGC)
}
---
04.GC性能分析
a.GC暂停时间
---
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var m runtime.MemStats
// 分配大量对象
for i := 0; i < 10; i++ {
data := make([][]byte, 10000)
for j := range data {
data[j] = make([]byte, 1024)
}
runtime.GC()
runtime.ReadMemStats(&m)
fmt.Printf("GC #%d:\n", m.NumGC)
fmt.Printf(" 暂停时间: %v\n",
time.Duration(m.PauseNs[(m.NumGC+255)%256]))
fmt.Printf(" HeapAlloc: %d MB\n", m.HeapAlloc/1024/1024)
_ = data
}
// 统计GC暂停
fmt.Println("\nGC暂停统计:")
fmt.Printf(" 总次数: %d\n", m.NumGC)
fmt.Printf(" 总暂停时间: %v\n", time.Duration(m.PauseTotalNs))
fmt.Printf(" 平均暂停: %v\n",
time.Duration(m.PauseTotalNs)/time.Duration(m.NumGC))
// 最近256次GC的暂停时间
fmt.Println("\n最近GC暂停时间:")
for i := 0; i < 10 && i < int(m.NumGC); i++ {
idx := (m.NumGC - uint32(i) + 255) % 256
fmt.Printf(" GC #%d: %v\n",
m.NumGC-uint32(i),
time.Duration(m.PauseNs[idx]))
}
}
---
3.2 GC触发时机
01.自动触发条件
a.堆内存阈值
a.功能说明
当堆内存达到上次GC后的2倍时(由GOGC控制),自动触发GC。默认GOGC=100,即增长100%触发。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
)
func main() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("初始状态:\n")
fmt.Printf(" HeapAlloc: %d KB\n", m.HeapAlloc/1024)
fmt.Printf(" NextGC: %d KB\n", m.NextGC/1024)
fmt.Printf(" GOGC: %d%%\n", debug.SetGCPercent(-1))
debug.SetGCPercent(100)
fmt.Println("\n开始分配内存...")
beforeGC := m.NumGC
data := make([][]byte, 0)
for {
data = append(data, make([]byte, 1024*1024))
runtime.ReadMemStats(&m)
if m.NumGC > beforeGC {
fmt.Printf("\nGC触发!\n")
fmt.Printf(" 触发时HeapAlloc: %d MB\n", m.HeapAlloc/1024/1024)
fmt.Printf(" NextGC: %d MB\n", m.NextGC/1024/1024)
break
}
}
_ = data
}
---
b.定时触发
a.功能说明
如果超过2分钟没有执行GC,会强制触发一次GC。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
lastGC := m.NumGC
data := make([]byte, 1024*1024)
_ = data
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for i := 0; i < 15; i++ {
<-ticker.C
runtime.ReadMemStats(&m)
if m.NumGC > lastGC {
fmt.Printf("定时GC触发! GC次数: %d\n", m.NumGC)
return
}
fmt.Printf("等待中... (GC次数: %d)\n", m.NumGC)
}
}
---
02.手动触发GC
a.runtime.GC函数
---
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var m runtime.MemStats
data := make([][]byte, 100)
for i := range data {
data[i] = make([]byte, 1024*1024)
}
runtime.ReadMemStats(&m)
fmt.Printf("分配后: HeapAlloc=%d MB, NumGC=%d\n",
m.HeapAlloc/1024/1024, m.NumGC)
for i := range data {
data[i] = nil
}
start := time.Now()
runtime.GC()
duration := time.Since(start)
runtime.ReadMemStats(&m)
fmt.Printf("GC后: HeapAlloc=%d MB, NumGC=%d, 耗时=%v\n",
m.HeapAlloc/1024/1024, m.NumGC, duration)
}
---
b.debug.FreeOSMemory
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
)
func main() {
var m runtime.MemStats
data := make([][]byte, 100)
for i := range data {
data[i] = make([]byte, 10*1024*1024)
}
runtime.ReadMemStats(&m)
fmt.Printf("分配后: HeapSys=%d MB, HeapReleased=%d MB\n",
m.HeapSys/1024/1024, m.HeapReleased/1024/1024)
data = nil
runtime.GC()
runtime.ReadMemStats(&m)
fmt.Printf("GC后: HeapSys=%d MB, HeapReleased=%d MB\n",
m.HeapSys/1024/1024, m.HeapReleased/1024/1024)
debug.FreeOSMemory()
runtime.ReadMemStats(&m)
fmt.Printf("FreeOSMemory后: HeapSys=%d MB, HeapReleased=%d MB\n",
m.HeapSys/1024/1024, m.HeapReleased/1024/1024)
}
---
03.GOGC控制
a.环境变量设置
---
// GOGC=100 (默认): 堆增长100%触发GC
GOGC=100 go run main.go
// GOGC=50: 更频繁GC
GOGC=50 go run main.go
// GOGC=200: 更少GC
GOGC=200 go run main.go
// GOGC=off: 禁用自动GC
GOGC=off go run main.go
---
b.动态调整
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
"time"
)
func testGOGC(percent int) {
debug.SetGCPercent(percent)
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
beforeGC := m.NumGC
start := time.Now()
for i := 0; i < 1000; i++ {
_ = make([]byte, 1024*1024)
}
duration := time.Since(start)
runtime.ReadMemStats(&m)
fmt.Printf("GOGC=%d: GC次数=%d, 耗时=%v\n",
percent, m.NumGC-beforeGC, duration)
}
func main() {
testGOGC(50)
testGOGC(100)
testGOGC(200)
}
---
3.3 写屏障
01.写屏障的作用
a.基本概念
写屏障是GC并发标记阶段的关键机制,用于记录指针修改,确保标记的正确性。
b.工作原理
当程序修改指针时,写屏障会拦截这个操作,确保新旧对象都被正确标记,防止对象被错误回收。
02.混合写屏障
a.实现机制
---
package main
import (
"fmt"
"runtime"
"sync"
)
type Node struct {
value int
next *Node
}
func main() {
var wg sync.WaitGroup
head := &Node{value: 1}
current := head
for i := 2; i <= 1000; i++ {
current.next = &Node{value: i}
current = current.next
}
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
current := head
for current != nil {
current.value++
current = current.next
}
}
}()
go func() {
defer wg.Done()
runtime.GC()
}()
wg.Wait()
fmt.Println("完成")
}
---
03.写屏障性能影响
a.性能开销
---
package main
import (
"fmt"
"runtime/debug"
"testing"
)
type Data struct {
ptr *int
}
func BenchmarkWithGC(b *testing.B) {
debug.SetGCPercent(100)
d := &Data{}
v := 42
b.ResetTimer()
for i := 0; i < b.N; i++ {
d.ptr = &v
}
}
func BenchmarkWithoutGC(b *testing.B) {
debug.SetGCPercent(-1)
d := &Data{}
v := 42
b.ResetTimer()
for i := 0; i < b.N; i++ {
d.ptr = &v
}
}
func main() {
r1 := testing.Benchmark(BenchmarkWithGC)
r2 := testing.Benchmark(BenchmarkWithoutGC)
fmt.Printf("启用GC: %s\n", r1.String())
fmt.Printf("禁用GC: %s\n", r2.String())
}
---
3.4 GC调优
01.GC调优目标
a.降低GC暂停时间
通过调整GOGC、优化对象分配等方式减少GC暂停。
b.减少GC频率
合理设置GOGC值,避免过于频繁的GC。
c.降低内存占用
及时释放不用的对象,避免内存泄漏。
02.调优参数
a.GOGC参数
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
)
func testGCTuning(gogc int) {
debug.SetGCPercent(gogc)
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
before := m.NumGC
for i := 0; i < 10000; i++ {
_ = make([]byte, 1024)
}
runtime.ReadMemStats(&m)
fmt.Printf("GOGC=%d: GC次数=%d, HeapAlloc=%d KB\n",
gogc, m.NumGC-before, m.HeapAlloc/1024)
}
func main() {
testGCTuning(50)
testGCTuning(100)
testGCTuning(200)
}
---
b.GOMEMLIMIT参数
---
// Go 1.19+ 支持内存限制
GOMEMLIMIT=1GiB go run main.go
---
03.代码层面优化
a.对象池复用
---
package main
import (
"fmt"
"runtime"
"sync"
)
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 1024)
},
}
func withoutPool() {
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
before := m.NumGC
for i := 0; i < 100000; i++ {
_ = make([]byte, 1024)
}
runtime.ReadMemStats(&m)
fmt.Printf("不使用Pool: GC次数=%d\n", m.NumGC-before)
}
func withPool() {
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
before := m.NumGC
for i := 0; i < 100000; i++ {
buf := bufferPool.Get().([]byte)
bufferPool.Put(buf)
}
runtime.ReadMemStats(&m)
fmt.Printf("使用Pool: GC次数=%d\n", m.NumGC-before)
}
func main() {
withoutPool()
withPool()
}
---
b.减少指针使用
---
package main
type WithPointer struct {
data *[1024]int
}
type WithoutPointer struct {
data [1024]int
}
func main() {
// 指针字段需要GC扫描
_ = make([]WithPointer, 1000)
// 无指针字段,GC扫描更快
_ = make([]WithoutPointer, 1000)
}
---
04.监控与分析
a.GC统计信息
---
package main
import (
"fmt"
"runtime"
"time"
)
func printGCStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("GC统计:\n")
fmt.Printf(" NumGC: %d\n", m.NumGC)
fmt.Printf(" PauseTotalNs: %v\n", time.Duration(m.PauseTotalNs))
fmt.Printf(" 平均暂停: %v\n",
time.Duration(m.PauseTotalNs)/time.Duration(m.NumGC))
fmt.Printf(" HeapAlloc: %d MB\n", m.HeapAlloc/1024/1024)
}
func main() {
for i := 0; i < 10; i++ {
_ = make([]byte, 10*1024*1024)
runtime.GC()
}
printGCStats()
}
---
3.5 GOGC环境变量
01.GOGC的含义
a.基本定义
GOGC控制GC触发的阈值,默认值100表示堆内存增长100%时触发GC。
b.计算公式
下次GC目标 = 上次GC后的存活堆大小 × (1 + GOGC/100)
02.GOGC设置方式
a.环境变量
---
// 默认值
GOGC=100 go run main.go
// 更频繁GC
GOGC=50 go run main.go
// 更少GC
GOGC=200 go run main.go
// 禁用自动GC
GOGC=off go run main.go
---
b.代码设置
---
package main
import (
"fmt"
"runtime/debug"
)
func main() {
old := debug.SetGCPercent(50)
fmt.Printf("旧值: %d, 新值: 50\n", old)
current := debug.SetGCPercent(-1)
debug.SetGCPercent(current)
fmt.Printf("当前值: %d\n", current)
}
---
03.GOGC对性能的影响
a.不同GOGC值对比
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
"time"
)
func benchmark(gogc int) {
debug.SetGCPercent(gogc)
var m runtime.MemStats
runtime.GC()
runtime.ReadMemStats(&m)
beforeGC := m.NumGC
beforeMem := m.TotalAlloc
start := time.Now()
for i := 0; i < 100000; i++ {
_ = make([]byte, 1024)
}
duration := time.Since(start)
runtime.ReadMemStats(&m)
fmt.Printf("GOGC=%d:\n", gogc)
fmt.Printf(" 耗时: %v\n", duration)
fmt.Printf(" GC次数: %d\n", m.NumGC-beforeGC)
fmt.Printf(" 分配内存: %d MB\n", (m.TotalAlloc-beforeMem)/1024/1024)
fmt.Printf(" 峰值内存: %d MB\n\n", m.HeapAlloc/1024/1024)
}
func main() {
benchmark(50)
benchmark(100)
benchmark(200)
}
---
04.GOGC使用建议
a.场景选择
---
// 内存受限环境(容器)
GOGC=50
// 高吞吐场景
GOGC=200
// 批处理任务
GOGC=off // 手动控制GC
---
b.动态调整
---
package main
import (
"runtime"
"runtime/debug"
)
func adjustGOGC() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
// 根据内存使用动态调整
if m.HeapAlloc > 1024*1024*1024 { // 超过1GB
debug.SetGCPercent(50) // 更频繁GC
} else {
debug.SetGCPercent(100) // 默认值
}
}
func main() {
adjustGOGC()
}
---
4 调度器:GMP模型
4.1 GMP模型详解
01.GMP模型组成
a.G(Goroutine)
代表一个goroutine,包含栈、程序计数器和goroutine的状态信息。
b.M(Machine)
代表一个操作系统线程,执行goroutine的实体。
c.P(Processor)
代表调度的上下文,维护goroutine队列,M必须绑定P才能执行G。
02.GMP工作流程
a.基本流程
---
package main
import (
"fmt"
"runtime"
"time"
)
func worker(id int) {
fmt.Printf("Worker %d 开始执行\n", id)
time.Sleep(100 * time.Millisecond)
fmt.Printf("Worker %d 完成\n", id)
}
func main() {
runtime.GOMAXPROCS(2)
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
for i := 0; i < 10; i++ {
go worker(i)
}
time.Sleep(500 * time.Millisecond)
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
}
---
03.调度策略
a.工作窃取
当P的本地队列为空时,会从其他P的队列窃取一半的goroutine。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
runtime.GOMAXPROCS(4)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
sum := 0
for j := 0; j < 1000000; j++ {
sum += j
}
}(i)
}
wg.Wait()
fmt.Println("完成")
}
---
4.2 G:Goroutine
01.Goroutine结构
a.栈空间
每个goroutine有独立的栈,初始2KB,可动态增长。
b.状态转换
---
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Printf("初始goroutines: %d\n", runtime.NumGoroutine())
go func() {
time.Sleep(100 * time.Millisecond)
}()
fmt.Printf("创建后: %d\n", runtime.NumGoroutine())
time.Sleep(200 * time.Millisecond)
fmt.Printf("完成后: %d\n", runtime.NumGoroutine())
}
---
02.Goroutine创建
a.创建开销
---
package main
import (
"fmt"
"testing"
)
func BenchmarkGoroutineCreation(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
go func() {}()
}
}
func main() {
result := testing.Benchmark(BenchmarkGoroutineCreation)
fmt.Printf("%s\n", result.String())
}
---
4.3 M:Machine线程
01.M的作用
a.执行实体
M是goroutine执行的实体,对应操作系统线程。
b.数量控制
---
package main
import (
"fmt"
"runtime"
"runtime/debug"
)
func main() {
debug.SetMaxThreads(100)
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
for i := 0; i < 1000; i++ {
go func() {
select {}
}()
}
fmt.Printf("Goroutines: %d\n", runtime.NumGoroutine())
}
---
4.4 P:Processor处理器
01.P的作用
a.调度上下文
P维护本地goroutine队列,提供调度上下文。
b.GOMAXPROCS设置
---
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func testWithProcs(procs int) {
runtime.GOMAXPROCS(procs)
var wg sync.WaitGroup
start := time.Now()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
sum := 0
for j := 0; j < 100000000; j++ {
sum += j
}
}()
}
wg.Wait()
duration := time.Since(start)
fmt.Printf("GOMAXPROCS=%d: %v\n", procs, duration)
}
func main() {
testWithProcs(1)
testWithProcs(2)
testWithProcs(4)
}
---
4.5 调度策略与抢占
01.协作式调度
a.主动让出
---
package main
import (
"fmt"
"runtime"
)
func main() {
for i := 0; i < 5; i++ {
go func(id int) {
for j := 0; j < 3; j++ {
fmt.Printf("G%d-%d ", id, j)
runtime.Gosched()
}
}(i)
}
runtime.Gosched()
fmt.Println()
}
---
02.抢占式调度
a.基于信号的抢占
Go 1.14+支持异步抢占,防止goroutine长时间占用CPU。
b.代码示例
---
package main
import (
"fmt"
"runtime"
"time"
)
func cpuBound() {
for {
// 长时间CPU密集计算
}
}
func main() {
runtime.GOMAXPROCS(1)
go cpuBound()
time.Sleep(100 * time.Millisecond)
fmt.Println("主goroutine仍能执行")
}
---
5 类型系统
5.1 类型元数据
01.类型信息
a.reflect.Type
---
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
p := Person{"Alice", 30}
t := reflect.TypeOf(p)
fmt.Printf("类型名: %s\n", t.Name())
fmt.Printf("类型种类: %s\n", t.Kind())
fmt.Printf("字段数: %d\n", t.NumField())
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fmt.Printf("字段%d: %s (%s)\n", i, field.Name, field.Type)
}
}
---
02.类型大小和对齐
a.unsafe.Sizeof
---
package main
import (
"fmt"
"unsafe"
)
func main() {
fmt.Printf("int: %d字节\n", unsafe.Sizeof(int(0)))
fmt.Printf("string: %d字节\n", unsafe.Sizeof(""))
fmt.Printf("[]int: %d字节\n", unsafe.Sizeof([]int{}))
fmt.Printf("map: %d字节\n", unsafe.Sizeof(map[string]int{}))
}
---
5.2 接口实现原理
01.接口结构
a.iface和eface
iface表示带方法的接口,eface表示空接口interface{}。
b.代码示例
---
package main
import "fmt"
type Animal interface {
Speak() string
}
type Dog struct {
name string
}
func (d Dog) Speak() string {
return "Woof"
}
func main() {
var a Animal = Dog{"Buddy"}
fmt.Println(a.Speak())
var e interface{} = Dog{"Max"}
fmt.Printf("%v\n", e)
}
---
02.类型断言
a.安全断言
---
package main
import "fmt"
func main() {
var i interface{} = "hello"
s, ok := i.(string)
if ok {
fmt.Printf("字符串: %s\n", s)
}
n, ok := i.(int)
if !ok {
fmt.Println("不是int类型")
}
_ = n
}
---
5.3 反射机制
01.反射基础
a.reflect包
---
package main
import (
"fmt"
"reflect"
)
func main() {
x := 42
v := reflect.ValueOf(x)
fmt.Printf("类型: %s\n", v.Type())
fmt.Printf("值: %v\n", v.Int())
fmt.Printf("可设置: %v\n", v.CanSet())
p := reflect.ValueOf(&x)
pv := p.Elem()
fmt.Printf("指针可设置: %v\n", pv.CanSet())
pv.SetInt(100)
fmt.Printf("新值: %d\n", x)
}
---
02.反射性能
a.性能对比
---
package main
import (
"fmt"
"reflect"
"testing"
)
type Data struct {
Value int
}
func BenchmarkDirect(b *testing.B) {
d := Data{Value: 42}
for i := 0; i < b.N; i++ {
_ = d.Value
}
}
func BenchmarkReflect(b *testing.B) {
d := Data{Value: 42}
v := reflect.ValueOf(d)
for i := 0; i < b.N; i++ {
_ = v.FieldByName("Value").Int()
}
}
func main() {
r1 := testing.Benchmark(BenchmarkDirect)
r2 := testing.Benchmark(BenchmarkReflect)
fmt.Printf("直接访问: %s\n", r1.String())
fmt.Printf("反射访问: %s\n", r2.String())
}
---
5.4 类型断言与类型转换
01.类型断言
a.单值断言
---
package main
import "fmt"
func main() {
var i interface{} = "hello"
s := i.(string)
fmt.Println(s)
// n := i.(int) // panic
}
---
b.安全断言
---
package main
import "fmt"
func main() {
var i interface{} = 42
if s, ok := i.(string); ok {
fmt.Println(s)
} else {
fmt.Println("不是string")
}
if n, ok := i.(int); ok {
fmt.Printf("是int: %d\n", n)
}
}
---
02.类型switch
a.多类型判断
---
package main
import "fmt"
func checkType(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("int: %d\n", v)
case string:
fmt.Printf("string: %s\n", v)
case bool:
fmt.Printf("bool: %v\n", v)
default:
fmt.Printf("unknown: %T\n", v)
}
}
func main() {
checkType(42)
checkType("hello")
checkType(true)
checkType(3.14)
}
---
6 性能分析与调试
6.1 pprof性能分析
01.CPU性能分析
a.基本使用
---
package main
import (
"os"
"runtime/pprof"
)
func main() {
f, _ := os.Create("cpu.prof")
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
// 业务代码
sum := 0
for i := 0; i < 100000000; i++ {
sum += i
}
}
// 分析: go tool pprof cpu.prof
---
02.内存性能分析
a.堆分析
---
package main
import (
"os"
"runtime/pprof"
)
func main() {
data := make([][]byte, 1000)
for i := range data {
data[i] = make([]byte, 1024*1024)
}
f, _ := os.Create("mem.prof")
defer f.Close()
pprof.WriteHeapProfile(f)
}
// 分析: go tool pprof mem.prof
---
03.HTTP pprof
a.Web界面
---
package main
import (
"net/http"
_ "net/http/pprof"
)
func main() {
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
select {}
}
// 访问: http://localhost:6060/debug/pprof/
---
01.数据竞争检测
a.使用race检测器
---
package main
import "fmt"
func main() {
counter := 0
go func() {
for i := 0; i < 1000; i++ {
counter++ // 数据竞争
}
}()
go func() {
for i := 0; i < 1000; i++ {
counter++ // 数据竞争
}
}()
fmt.Println(counter)
}
// 运行: go run -race main.go
---
02.修复竞态
a.使用互斥锁
---
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
counter := 0
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
mu.Lock()
counter++
mu.Unlock()
}
}()
go func() {
defer wg.Done()
for i := 0; i < 1000; i++ {
mu.Lock()
counter++
mu.Unlock()
}
}()
wg.Wait()
fmt.Println(counter)
}
---
6.4 GODEBUG调试
01.GODEBUG环境变量
a.GC调试
---
// 打印GC信息
GODEBUG=gctrace=1 go run main.go
// 打印调度信息
GODEBUG=schedtrace=1000 go run main.go
// 打印内存分配
GODEBUG=allocfreetrace=1 go run main.go
---
02.调试示例
a.GC追踪
---
package main
import "time"
func main() {
for i := 0; i < 10; i++ {
_ = make([]byte, 10*1024*1024)
time.Sleep(100 * time.Millisecond)
}
}
// 运行: GODEBUG=gctrace=1 go run main.go
---
6.5 性能优化建议
01.常见优化技巧
a.减少内存分配
---
package main
import "sync"
var bufferPool = sync.Pool{
New: func() interface{} {
return make([]byte, 1024)
},
}
func process() {
buf := bufferPool.Get().([]byte)
defer bufferPool.Put(buf)
// 使用buf
}
func main() {
for i := 0; i < 1000; i++ {
process()
}
}
---
02.并发优化
a.控制goroutine数量
---
package main
import "sync"
func main() {
tasks := make(chan int, 100)
var wg sync.WaitGroup
// 限制并发数为10
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for task := range tasks {
// 处理任务
_ = task
}
}()
}
for i := 0; i < 1000; i++ {
tasks <- i
}
close(tasks)
wg.Wait()
}
---
03.性能基准测试
a.编写benchmark
---
package main
import "testing"
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
func BenchmarkFibonacci(b *testing.B) {
for i := 0; i < b.N; i++ {
fibonacci(20)
}
}
// 运行: go test -bench=. -benchmem
---