如何在golang中手动释放内存

huangapple go评论86阅读模式
英文:

How to free memory manually in golang

问题

以下是计算C(36,8)并将结果保存到文件的代码:

func combine_dfs(n int, k int) (ans [][]int) {
	temp := []int{}
	var dfs func(int)
	dfs = func(cur int) {
		if len(temp)+(n-cur+1) < k {
			return
		}
		if len(temp) == k {
			comb := make([]int, k)
			copy(comb, temp)
			ans = append(ans, comb)
			return
		}
		temp = append(temp, cur)
		dfs(cur + 1)
		temp = temp[:len(temp)-1]
		dfs(cur + 1)
	}
	dfs(1)
	return
}

func DoCombin() {
	fmt.Printf("%v\n", "calculator...")
	cst := []byte{}
	for i := 'a'; i <= 'z'; i++ {
		cst = append(cst, byte(i))
	}
	for i := '0'; i <= '9'; i++ {
		cst = append(cst, byte(i))
	}
	n := 36
	k := 8
	arr := combine_dfs(n, k)
	fmt.Printf("%v\n", "writefile...")
	file, _ := os.OpenFile("result.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
	defer file.Close()
	for _, m := range arr {
		b := bytes.Buffer{}
		b.Reset()
		for _, i := range m {
			b.WriteByte(cst[i-1])
		}
		b.WriteByte('\n')
		file.Write(b.Bytes())
	}
}

但是写文件的速度很慢,所以我想使用goroutine来写文件(使用池来限制goroutine的数量):

func DoCombin2() {
	fmt.Printf("%v\n", "calculator...")
	cst := []byte{}
	for i := 'a'; i <= 'z'; i++ {
		cst = append(cst, byte(i))
	}
	for i := '0'; i <= '9'; i++ {
		cst = append(cst, byte(i))
	}
	n := 36
	k := 8
	arr := combine_dfs(n, k)
	fmt.Printf("%v\n", "writefile...")
	file, _ := os.OpenFile("result.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
	defer file.Close()
	pool := make(chan int, 100)
	for _, m := range arr {
		go func(m []int) {
			pool <- 1
			b := bytes.Buffer{}
			b.Reset()
			for _, i := range m {
				b.WriteByte(cst[i-1])
			}
			b.WriteByte('\n')
			file.Write(b.Bytes())
			<-pool
		}(m)
	}
}

但是内存爆炸了。

我尝试使用sync.Pool来避免内存爆炸,但失败了:

var bufPool = sync.Pool{
	New: func() interface{} {
		return new(bytes.Buffer)
	},
}

func DoCombin() {
	fmt.Printf("%v\n", "calculator...")
	cst := []byte{}
	for i := 'a'; i <= 'z'; i++ {
		cst = append(cst, byte(i))
	}
	for i := '0'; i <= '9'; i++ {
		cst = append(cst, byte(i))
	}
	n := 36
	k := 8
	arr := combine_dfs(n, k)
	fmt.Printf("%v\n", "writefile...")
	file, _ := os.OpenFile("result.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
	defer file.Close()
	pool := make(chan int, 100)
	for _, m := range arr {
		go func(m []int) {
			pool <- 1
			b, _ := bufPool.Get().(*bytes.Buffer)
			b.Reset()
			for _, i := range m {
				b.WriteByte(cst[i-1])
			}
			b.WriteByte('\n')
			bufPool.Put(b)
			file.Write(b.Bytes())
			<-pool
		}(m)
	}
}

有没有办法避免内存爆炸?

  1. 使用sync.Pool后为什么无法避免内存爆炸?
  2. 在Windows中有没有办法限制内存使用?(在Linux中我知道)
  3. 有没有其他方法可以避免内存爆炸?
  4. 内存爆炸是因为bytes.Buffer吗?如何手动释放bytes.Buffer?
英文:

Below is a code to calculte C(36,8) and save result to file

func combine_dfs(n int, k int) (ans [][]int) {
temp := []int{}
var dfs func(int)
dfs = func(cur int) {
if len(temp)+(n-cur+1) &lt; k {
return
}
if len(temp) == k {
comb := make([]int, k)
copy(comb, temp)
ans = append(ans, comb)
return
}
temp = append(temp, cur)
dfs(cur + 1)
temp = temp[:len(temp)-1]
dfs(cur + 1)
}
dfs(1)
return
}
func DoCombin() {
fmt.Printf(&quot;%v\n&quot;, &quot;calculator...&quot;)
cst := []byte{}
for i := &#39;a&#39;; i &lt;= &#39;z&#39;; i++ {
cst = append(cst, byte(i))
}
for i := &#39;0&#39;; i &lt;= &#39;9&#39;; i++ {
cst = append(cst, byte(i))
}
n := 36
k := 8
arr := combine_dfs(n, k)
fmt.Printf(&quot;%v\n&quot;, &quot;writefile...&quot;)
file, _ := os.OpenFile(&quot;result.txt&quot;, os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
defer file.Close()
for _, m := range arr {
b:= bytes.Buffer{}
b.Reset()
for _, i := range m {
b.WriteByte(cst[i-1])
}
b.WriteByte(&#39;\n&#39;)
file.Write(b.Bytes())
}
}

but i write file so slow..

so i want use goroutine to write file (use pool to limit the number of goroutine):

func DoCombin2() {
fmt.Printf(&quot;%v\n&quot;, &quot;calculator...&quot;)
cst := []byte{}
for i := &#39;a&#39;; i &lt;= &#39;z&#39;; i++ {
cst = append(cst, byte(i))
}
for i := &#39;0&#39;; i &lt;= &#39;9&#39;; i++ {
cst = append(cst, byte(i))
}
n := 36
k := 8
arr := combine_dfs(n, k)
fmt.Printf(&quot;%v\n&quot;, &quot;writefile...&quot;)
file, _ := os.OpenFile(&quot;result.txt&quot;, os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
defer file.Close()
pool := make(chan int, 100)
for _, m := range arr {
go func(m []int) {
pool &lt;- 1
b := bytes.Buffer{}
b.Reset()
for _, i := range m {
b.WriteByte(cst[i-1])
}
b.WriteByte(&#39;\n&#39;)
file.Write(b.Bytes())
&lt;-pool
}(m)
}
}

but the memory exploded

I try using sync.Pool to avoid it, but it fail:

var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func DoCombin() {
fmt.Printf(&quot;%v\n&quot;, &quot;calculator...&quot;)
cst := []byte{}
for i := &#39;a&#39;; i &lt;= &#39;z&#39;; i++ {
cst = append(cst, byte(i))
}
for i := &#39;0&#39;; i &lt;= &#39;9&#39;; i++ {
cst = append(cst, byte(i))
}
n := 36
k := 8
arr := combine_dfs(n, k)
fmt.Printf(&quot;%v\n&quot;, &quot;writefile...&quot;)
file, _ := os.OpenFile(&quot;result.txt&quot;, os.O_CREATE|os.O_TRUNC|os.O_RDWR|os.O_APPEND, 0666)
defer file.Close()
pool := make(chan int, 100)
for _, m := range arr {
go func(m []int) {
pool &lt;- 1
b, _ := bufPool.Get().(*bytes.Buffer)
b.Reset()
for _, i := range m {
b.WriteByte(cst[i-1])
}
b.WriteByte(&#39;\n&#39;)
bufPool.Put(b)
file.Write(b.Bytes())
&lt;-pool
}(m)
}
}

Is there any way to avoid memory explosion?

  • 1.Why can't I avoid it after using sync.Pool?
  • 2.Is there any way to limit memory usage in windows(in linux i know) ?
  • 3.Is there other way to avoid memory explosion?
  • 4.Is the memory explosion because of bytes.Buffer? How to free bytes.Buffer manually?

答案1

得分: 0

在Go 1.19中,垃圾收集器增加了对软内存限制的支持。详细信息可以在新的垃圾收集指南中找到。这个限制对于优化Go程序以在具有专用内存量的容器中尽可能高效地运行非常有帮助。新的垃圾收集指南

英文:

in go 1.19

The garbage collector has added support for a soft memory limit,
> The garbage collector has added support for a soft memory limit, discussed in detail in the new garbage collection guide. The limit can be particularly helpful for optimizing Go programs to run as efficiently as possible in containers with dedicated amounts of memory.

the new garbage collection guide

答案2

得分: 0

更新日期:2023年02月20日

由于严重的API问题,该提案“arenas”无限期暂停。GOEXPERIMENT=arena代码可能会发生不兼容的更改或被随时删除,我们不建议在生产环境中使用

根据这个提案:arena:提供内存区域的新包

我们提议在Go标准库中添加一个新的arena包。arena包将允许分配任意数量的内存区域。可以从arena的内存中分配任意类型的对象,并且arena会根据需要自动增长。当arena中的所有对象不再使用时,可以显式释放arena以高效地回收其内存,而无需进行常规垃圾回收。我们要求实现提供安全检查,以便如果arena的释放操作不安全,程序将在发生任何错误行为之前终止。

此功能已合并到主分支中的arena可能会在go 1.20中发布。使用arena包,您可以自己分配内存,并在不再使用时手动释放它。

示例代码

	a := arena.NewArena()
	defer a.Free()

	tt := arena.New[T1](a)
	tt.n = 1

	ts := arena.MakeSlice[T1](a, 99, 100)
	if len(ts) != 99 {
		t.Errorf("Slice() len = %d, want 99", len(ts))
	}
	if cap(ts) != 100 {
		t.Errorf("Slice() cap = %d, want 100", cap(ts))
	}
	ts[1].n = 42
英文:

Update 02/20/2023

> This proposal arenas is on hold indefinitely due to serious API concerns. The GOEXPERIMENT=arena code may be changed incompatibly or removed at any time, and we do not recommend its use in production.


Per this Proposal: arena: new package providing memory arenas

> We propose the addition of a new arena package to the Go standard library. The arena package will allow the allocation of any number of arenas. Objects of arbitrary type can be allocated from the memory of the arena, and an arena automatically grows in size as needed. When all objects in an arena are no longer in use, the arena can be explicitly freed to reclaim its memory efficiently without general garbage collection. We require that the implementation provide safety checks, such that, if an arena free operation is unsafe, the program will be terminated before any incorrect behavior happens.

This feature has been merged to the master branch under arena, and maybe could be released in go 1.20. With the arena package, you could allocate memory by yourself and manually free it if it is no longer in use.

Sample codes

	a := arena.NewArena()
	defer a.Free()

	tt := arena.New[T1](a)
	tt.n = 1

	ts := arena.MakeSlice[T1](a, 99, 100)
	if len(ts) != 99 {
		t.Errorf(&quot;Slice() len = %d, want 99&quot;, len(ts))
	}
	if cap(ts) != 100 {
		t.Errorf(&quot;Slice() cap = %d, want 100&quot;, cap(ts))
	}
	ts[1].n = 42

huangapple
  • 本文由 发表于 2022年6月2日 13:25:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/72471052.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定