Golang内存泄漏问题紧急求助!
Golang内存泄漏问题紧急求助!
// test project main.go
package main
import (
"fmt"
"math/big"
"os"
"runtime"
"sync"
"time"
)
var file, _ = os.Create("20-1.txt")
var round = 1
var input = 3
var size = 1048576
var block = 8192
var s_box = [16][16]int{
{16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //0
{0, 0, 0, 4, 0, 0, 0, 4, 0, 4, 0, 0, 0, 4, 0, 0}, //1
{0, 0, 0, 2, 0, 4, 2, 0, 0, 0, 2, 0, 2, 2, 2, 0}, //2
{0, 2, 0, 2, 2, 0, 4, 2, 0, 0, 2, 2, 0, 0, 0, 0}, //3
{0, 0, 0, 0, 0, 4, 2, 2, 0, 2, 2, 0, 2, 0, 2, 0}, //4
{0, 2, 0, 0, 2, 0, 0, 0, 0, 2, 2, 2, 4, 2, 0, 0}, //5
{0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 4, 2, 0, 0, 4}, //6
{0, 4, 2, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 4}, //7
{0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 4, 0, 2, 0, 4}, //8
{0, 0, 2, 0, 4, 0, 2, 0, 2, 0, 0, 0, 2, 0, 4, 0}, //9
{0, 0, 2, 2, 0, 4, 0, 0, 2, 0, 2, 0, 0, 2, 2, 0}, //A
{0, 2, 0, 0, 2, 0, 0, 0, 4, 2, 2, 2, 0, 2, 0, 0}, //B
{0, 0, 2, 0, 0, 4, 0, 2, 2, 2, 2, 0, 0, 0, 2, 0}, //C
{0, 2, 4, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0}, //D
{0, 0, 2, 2, 0, 0, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0}, //E
{0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4}} //F
func SPN(a []big.Rat, b [][]big.Rat, base int) {
for k := base * block; k < (base+1)*block; k++ {
//fmt.Println(k)
if a[k].Cmp(big.NewRat(0, 1)) > 0 {
first := k / 65536
second := k / 4096 % 16
third := k / 256 % 16
fourth := k / 16 % 16
fifth := k % 16
for m := 0; m < 16; m++ {
for n := 0; n < 16; n++ {
for x := 0; x < 16; x++ {
for y := 0; y < 16; y++ {
for z := 0; z < 16; z++ {
per := int64(s_box[first][m] * s_box[second][n] * s_box[third][x] * s_box[fourth][y] * s_box[fifth][z])
if per > 0 {
temp := big.NewRat(per, 1048576)
temp.Mul(temp, &a[k])
tt := m*65536 + n*4096 + x*256 + y*16 + z
var pos [20]int
for i := 0; i < 20; i++ {
pos[i] = tt % 2
tt >>= 1
tt = 524288*pos[19] + 16384*pos[18] + 512*pos[17] + 16*pos[16] + 262144*pos[15] + 8192*pos[14] + 256*pos[13] + 8*pos[12] + 131072*pos[11] + 4096*pos[10] +
128*pos[9] + 4*pos[8] + 65536*pos[7] + 2048*pos[6] + 64*pos[5] + 2*pos[4] + 32768*pos[3] + 1024*pos[2] + 32*pos[1] + 1*pos[0]
b[base][tt].Add(temp, &b[base][tt])
}
}
}
}
}
}
}
}
}
}
func main() {
start := time.Now()
runtime.GOMAXPROCS(128)
var wg sync.WaitGroup
var a = make([]big.Rat, size)
var b = make([][]big.Rat, 128)
var c = make([]big.Rat, size)
var dot string
for i := 0; i < 128; i++ {
b[i] = make([]big.Rat, size)
}
a[input].SetFrac(big.NewInt(1), big.NewInt(1))
change := a[:]
fmt.Printf("%v", a[input].String())
for i := 0; i < round; i++ {
for j := 0; j < 128; j++ {
//fmt.Printf("%d", j)
wg.Add(1)
go func(wg *sync.WaitGroup, j int) {
//SPN(a, b[j], j)
SPN(a, b, j)
for i := block * j; i < block*(j+1); i++ {
a[i].SetFrac(big.NewInt(0), big.NewInt(1))
}
for i := 0; i < size; i++ {
c[i].Add(&c[i], &b[j][i])
b[j][i].SetFrac(big.NewInt(0), big.NewInt(1))
}
defer wg.Done()
}(&wg, j)
}
wg.Wait()
change = a
a = c
c = change
/*for i := 0; i < 128; i++ {
for j := 0; j < size; j++ {
a[j].Add(&a[j], &b[i][j])
}
}
for i := 0; i < 128; i++ {
for j := 0; j < size; j++ {
b[i][j].SetFrac(big.NewInt(0), big.NewInt(1))
}
}*/
}
for i := 1; i < size; i++ {
dot = a[i].FloatString(20)
file.WriteString(dot + "\r\n")
}
elapsed := time.Since(start)
fmt.Printf("\nTook %s\n", elapsed)
}
结果如下:

更多关于Golang内存泄漏问题紧急求助!的实战教程也可以访问 https://www.itying.com/category-94-b0.html
非常感谢您有用的回答,我确实学到了很多知识。我想知道您是如何了解内存使用比例的?
你的环境是什么(架构、操作系统等)?看起来你只是向操作系统请求了超出其愿意分配的内存。
你是否知道如何快速将 b[][] 设置为 (“0/1”),因为在我的问题中,生成它的速度是最慢的
我在我的Linux系统上尝试运行它,该系统具有8GB内存和8GB交换空间。在系统将其终止之前,它消耗了所有的内存和交换空间。
Dench:
我想知道你是如何确定内存使用比例的?
我不太明白您的问题。我是如何计算 b 的大小的?我只是将数组的大小乘以其包含的每个数组的大小,再乘以 big.Rat 类型的大小。
Dench:
以及你是否知道如何快速将 b 设置为 (“0/1”),因为在我的问题中,生成它的速度是最慢的
抱歉,这个问题我也没理解。您能再解释一下吗?
我理解您是在询问错误信息的含义,而不是在查找所有内存分配发生的位置。所以我运行并进行了性能分析,如果您感兴趣的话。这是将 GOMAXPROCS 设置为 4 时的结果:

这是原始 128 GOMAXPROCS 的情况(运行速度快了几秒,但几乎使您的系统无法使用):

但我认为您不应该感到惊讶,您确实在分配大量内存。以 b 为例,它是 128 * 1048576 * 32(big.Rat 的大小)= 4294967296 字节,即仅此一项就超过 4 GB(或者正好是 4 GiB,即 2^32 字节,如预期的那样)。
分析您的代码,我发现了几个可能导致内存泄漏的问题:
主要问题分析
1. big.Rat 对象的大量创建和操作
在 SPN 函数中,每次循环都创建新的 big.Rat 对象,这会导致大量内存分配:
temp := big.NewRat(per, 1048576) // 每次循环都创建新对象
temp.Mul(temp, &a[k])
2. 嵌套循环过深
5层嵌套循环会产生大量迭代,每次迭代都涉及内存分配:
for m := 0; m < 16; m++ {
for n := 0; n < 16; n++ {
for x := 0; x < 16; x++ {
for y := 0; y < 16; y++ {
for z := 0; z < 16; z++ {
// 内存分配操作
}
}
}
}
}
3. 切片 b 的内存管理
b 是一个二维切片,每个元素都是 big.Rat,在并发环境下频繁操作:
var b = make([][]big.Rat, 128)
for i := 0; i < 128; i++ {
b[i] = make([]big.Rat, size) // 1048576 个 big.Rat
}
修复方案
1. 重用 big.Rat 对象
func SPN(a []big.Rat, b [][]big.Rat, base int) {
// 预分配临时变量
temp := new(big.Rat)
result := new(big.Rat)
for k := base * block; k < (base+1)*block; k++ {
if a[k].Cmp(big.NewRat(0, 1)) > 0 {
// ... 循环逻辑保持不变
for z := 0; z < 16; z++ {
per := int64(s_box[first][m] * s_box[second][n] * s_box[third][x] * s_box[fourth][y] * s_box[fifth][z])
if per > 0 {
// 重用 temp 而不是新建
temp.SetFrac64(per, 1048576)
temp.Mul(temp, &a[k])
tt := m*65536 + n*4096 + x*256 + y*16 + z
var pos [20]int
for i := 0; i < 20; i++ {
pos[i] = tt % 2
tt >>= 1
tt = 524288*pos[19] + 16384*pos[18] + 512*pos[17] + 16*pos[16] + 262144*pos[15] + 8192*pos[14] + 256*pos[13] + 8*pos[12] + 131072*pos[11] + 4096*pos[10] +
128*pos[9] + 4*pos[8] + 65536*pos[7] + 2048*pos[6] + 64*pos[5] + 2*pos[4] + 32768*pos[3] + 1024*pos[2] + 32*pos[1] + 1*pos[0]
// 重用 result 进行加法操作
result.Add(&b[base][tt], temp)
b[base][tt].Set(result)
}
}
}
}
}
}
2. 优化内存清理
func main() {
// ... 初始化代码
for i := 0; i < round; i++ {
for j := 0; j < 128; j++ {
wg.Add(1)
go func(wg *sync.WaitGroup, j int) {
defer wg.Done()
SPN(a, b, j)
// 使用 SetInt64 而不是 SetFrac 来避免内存分配
for i := block * j; i < block*(j+1); i++ {
a[i].SetInt64(0)
}
for i := 0; i < size; i++ {
c[i].Add(&c[i], &b[j][i])
b[j][i].SetInt64(0) // 重用对象而不是创建新对象
}
}(&wg, j)
}
wg.Wait()
change = a
a = c
c = change
}
// ... 后续代码
}
3. 添加内存监控
func printMemStats() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc))
fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc))
fmt.Printf("\tSys = %v MiB", bToMb(m.Sys))
fmt.Printf("\tNumGC = %v\n", m.NumGC)
}
func bToMb(b uint64) uint64 {
return b / 1024 / 1024
}
// 在 main 函数中定期调用
func main() {
go func() {
for {
time.Sleep(5 * time.Second)
printMemStats()
}
}()
// ... 原有逻辑
}
关键改进点
- 重用
big.Rat对象:避免在循环中频繁创建新对象 - 使用
SetInt64替代SetFrac:减少内存分配 - 预分配临时变量:在循环外创建变量并在循环内重用
- 添加内存监控:帮助诊断内存使用情况
这些修改应该能显著减少内存分配和垃圾回收压力,解决内存泄漏问题。

