首次提交:初始化项目代码
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// leakSlice 全局切片,持续追加数据导致内存泄漏
|
||||
var leakSlice [][]byte
|
||||
|
||||
// generateLeak 模拟内存泄漏
|
||||
func generateLeak() {
|
||||
for {
|
||||
// 每次分配10MB,追加到全局切片(永久引用,无法回收)
|
||||
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
// 打印当前内存状态
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
fmt.Printf("当前堆内存:%d MB,GC次数:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
|
||||
}
|
||||
}
|
||||
|
||||
func generateLeak1() {
|
||||
var maxMem uint64 = 500 // 最大允许占用500MB内存
|
||||
for {
|
||||
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
curMem := stats.HeapAlloc / 1024 / 1024
|
||||
fmt.Printf("当前堆内存:%d MB,GC次数:%d\n", curMem, stats.NumGC)
|
||||
|
||||
// ✅ 核心修复:内存超限后,置空全局切片,切断引用
|
||||
if curMem >= maxMem {
|
||||
leakSlice = nil // 关键一行!置空后,原切片的所有[]byte都失去引用
|
||||
runtime.GC() // 手动触发GC,立刻回收内存
|
||||
fmt.Println("=== 内存超限,已释放所有内存 ===")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateLeak2() {
|
||||
maxLen := 20 // 最多保留20个10MB切片,总内存上限200MB
|
||||
for {
|
||||
leakSlice = append(leakSlice, make([]byte, 10*1024*1024))
|
||||
// ✅ 核心修复:超过最大长度,删除头部旧数据,释放引用
|
||||
if len(leakSlice) > maxLen {
|
||||
leakSlice = leakSlice[1:] // 切片切片,丢弃第一个元素,GC会回收它
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
fmt.Printf("当前堆内存:%d MB,GC次数:%d,切片长度:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC, len(leakSlice))
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ 定义10MB切片的对象池
|
||||
var needBytePool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make([]byte, 10*1024*1024) // 每次创建10MB切片
|
||||
},
|
||||
}
|
||||
|
||||
// 无内存泄漏!复用内存,不持有永久引用
|
||||
func generateLeak3() {
|
||||
for {
|
||||
// 从池子里拿切片,复用内存
|
||||
buf := needBytePool.Get().([]byte)
|
||||
// 模拟业务使用
|
||||
_ = buf
|
||||
// 使用完放回池子,供后续复用,释放引用
|
||||
needBytePool.Put(buf[:0])
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
var stats runtime.MemStats
|
||||
runtime.ReadMemStats(&stats)
|
||||
fmt.Printf("当前堆内存:%d MB,GC次数:%d\n", stats.HeapAlloc/1024/1024, stats.NumGC)
|
||||
}
|
||||
}
|
||||
func main() {
|
||||
// 启动pprof服务
|
||||
go func() {
|
||||
log.Println("pprof服务启动:http://localhost:6060/debug/pprof/")
|
||||
log.Fatal(http.ListenAndServe(":6060", nil))
|
||||
}()
|
||||
|
||||
// 模拟内存泄漏
|
||||
go generateLeak3()
|
||||
|
||||
// 运行60秒,便于诊断
|
||||
time.Sleep(60 * time.Second)
|
||||
}
|
||||
Reference in New Issue
Block a user