Files
interview/questions/13-Golang语言/go-memory-model.md
yasinshaw ab3a99f131 feat: add 10 Golang interview questions
Added comprehensive Golang interview preparation materials:
- 基础语法(值类型、切片、map、defer、接口、struct、new/make)
- Goroutine 和并发模型(与线程对比、调度模型、内存模型)
- 错误处理和测试(error、panic/recover、单元测试、Benchmark)
- 并发编程进阶(Mutex、RWMutex、WaitGroup、atomic、数据竞争)
- HTTP 和 Web 开发(Client、Server、中间件模式)
- 内存模型和垃圾回收(内存分配、逃逸分析、GC)
- 性能优化(pprof、内存优化、CPU优化、并发优化)
- 反射和 unsafe(反射性能、unsafe 使用场景)
- 接口和类型系统(类型断言、interface{}、类型嵌入、泛型)
- 数据库操作(database/sql、GORM、事务、SQL 注入防护)
- 项目结构和工程化(标准项目结构、Go Module、CI/CD)

Each file includes:
- Detailed questions and comprehensive answers
- Code examples and best practices
- Alibaba P7 level requirements

Total: 60 interview questions (50 backend + 10 Golang)

Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
2026-03-01 00:16:36 +08:00

261 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Golang 内存模型和垃圾回收
## 问题
1. Go 的内存分配策略是什么?
2. Go 的垃圾回收GC是如何工作的
3. 什么是逃逸分析?
4. Go 的内存泄漏常见场景有哪些?
5. sync.Pool 的作用是什么?
6. 如何优化 Go 程序的内存使用?
---
## 标准答案
### 1. 内存分配策略
#### **堆和栈**
**栈Stack**
- 存储局部变量
- 自动分配和释放
- 速度快
```go
func foo() int {
x := 1 // 分配在栈上
return x
} // x 自动释放
```
---
**堆Heap**
- 存储动态分配的数据
- 需要 GC 回收
```go
func foo() *int {
x := 1
return &x // x 逃逸到堆上
}
```
---
#### **逃逸分析**
**定义**:编译器分析变量的生命周期,决定分配在栈还是堆。
**示例**
```go
// ❌ 逃逸到堆
func foo() *int {
x := 1
return &x // x 的引用被返回,必须分配在堆上
}
// ✅ 不逃逸,分配在栈上
func bar() int {
x := 1
return x // x 的值被返回,可以分配在栈上
}
```
---
### 2. Go 的垃圾回收
#### **GC 算法:三色标记法 + 并发标记清理**
**三色标记**
- **白色**:未访问
- **灰色**:已访问,但引用的对象未全部访问
- **黑色**:已访问,引用的对象也全部访问
**流程**
```
1. 根节点标记为灰色
2. 遍历引用对象,标记为灰色
3. 递归标记,直到所有可达对象为黑色
4. 清扫白色对象(垃圾)
```
---
#### **GC 触发条件**
```go
// 环境变量
// GOGC触发 GC 的堆增长率(默认 100
// GOMEMLIMIT触发 GC 的堆内存上限
// 示例
GOGC=100 // 堆增长 100% 时触发 GC
GOMEMLIMIT=8192 // 堆上限 8 GB
```
---
### 3. 常见内存泄漏场景
#### **场景 1Goroutine 泄漏**
```go
// ❌ 泄漏
func leak() {
for i := 0; i < 100; i++ {
go func() {
time.Sleep(time.Hour) // 永不退出
}()
}
}
```
**解决**
```go
func noLeak() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
for i := 0; i < 100; i++ {
go func(ctx context.Context) {
select {
case <-ctx.Done():
return
case <-time.After(time.Hour):
}
}(ctx)
}
}
```
---
#### **场景 2切片引用**
```go
// ❌ 泄漏
func leak() {
for i := 0; i < 1000; i++ {
s := make([]int, 1024)
_ = append(s, i)
// s 被全局变量引用,无法 GC
}
}
```
---
### 4. sync.Pool
#### **作用**
**对象池**:复用对象,减少 GC 压力
---
#### **示例**
```go
var pool = sync.Pool{
New: func() interface{} {
return make([]byte, 1024)
},
}
func process() {
// 从池中获取
buf := pool.Get().([]byte)
// 使用
// ...
// 归还到池中
pool.Put(buf)
}
```
---
#### **适用场景**
- 频繁创建的对象([]byte、Buffer
- 临时对象(减少 GC
- 对象创建成本高
---
### 5. 内存优化技巧
#### **1. 预分配切片容量**
```go
// ❌ 多次扩容
s := []int{}
for i := 0; i < 1000; i++ {
s = append(s, i) // 多次扩容和拷贝
}
// ✅ 预分配
s := make([]int, 0, 1000)
for i := 0; i < 1000; i++ {
s = append(s, i) // 无扩容
}
```
---
#### **2. 使用 strings.Builder**
```go
// ❌ 字符串拼接(内存拷贝)
s := ""
for i := 0; i < 1000; i++ {
s += fmt.Sprintf("%d", i) // 每次都创建新字符串
}
// ✅ strings.Builder
var b strings.Builder
for i := 0; i < 1000; i++ {
b.WriteString(strconv.Itoa(i))
}
s := b.String() // 只分配一次
```
---
#### **3. 避免不必要的指针**
```go
// ❌ 使用指针(增加 GC 扫描时间)
type User struct {
Name *string
}
// ✅ 使用值类型
type User struct {
Name string
}
```
---
### 6. 阿里 P7 加分项
**深度理解**
- 理解 Go 的内存分配策略(栈、堆、逃逸分析)
- 理解 Go GC 的三色标记法
- 理解 GC 的触发条件和调优参数
**实战经验**
- 有使用 pprof 进行内存分析的经验
- 有优化内存使用的经验(减少 GC、复用对象
- 有处理内存泄漏的经验
**性能优化**
- 理解如何减少内存分配sync.Pool、预分配
- 理解如何减少 GC 压力(避免指针、复用对象)
- 理解如何使用 pprof 进行性能分析