gpt4 book ai didi

memory-management - Go 内存消耗管理

转载 作者:IT老高 更新时间:2023-10-28 13:01:28 26 4
gpt4 key购买 nike

我是 Go 新手,并试图弄清楚它是如何管理内存消耗的。

在我的一个测试项目中,我的内存力有问题。我不明白为什么当我的程序运行很长时间时,Go 会使用越来越多的内存(从不释放它)。

我正在运行下面提供的测试用例。第一次分配后,程序使用了近 350 MB 的内存(根据 ActivityMonitor)。然后我尝试释放它,ActivityMonitor 显示内存消耗翻了一番。为什么?

我正在使用 Go 1.0.3 在 OS X 上运行此代码。

这段代码有什么问题?在 Go 程序中管理大变量的正确方法是什么?

在实现一个使用大量时间和内存的算法时,我遇到了另一个与内存管理相关的问题;运行一段时间后,它会引发“内存不足”异常。

package main

import ("fmt"
"time"
)

func main() {
fmt.Println("getting memory")
tmp := make([]uint32, 100000000)
for kk, _ := range tmp {
tmp[kk] = 0
}
time.Sleep(5 * time.Second)
fmt.Println("returning memory")
tmp = make([]uint32, 1)
tmp = nil
time.Sleep(5 * time.Second)
fmt.Println("getting memory")
tmp = make([]uint32, 100000000)
for kk, _ := range tmp {
tmp[kk] = 0
}
time.Sleep(5 * time.Second)
fmt.Println("returning memory")
tmp = make([]uint32, 1)
tmp = nil
time.Sleep(5 * time.Second)
return
}

最佳答案

目前,go 使用 mark-and-sweep garbage collector ,一般不会定义对象何时被丢弃。

但是,如果您仔细观察,有一个名为 sysmon 的 go 例程。它基本上只要你的程序运行并定期调用 GC:

// forcegcperiod is the maximum time in nanoseconds between garbage
// collections. If we go this long without a garbage collection, one
// is forced to run.
//
// This is a variable for testing purposes. It normally doesn't change.
var forcegcperiod int64 = 2 * 60 * 1e9

(...)

// If a heap span goes unused for 5 minutes after a garbage collection,
// we hand it back to the operating system.
scavengelimit := int64(5 * 60 * 1e9)

forcegcperiod确定强制调用 GC 的时间段。 scavengelimit确定跨度何时返回到操作系统。 Spans are a number of memory pages它可以容纳多个对象。它们会保留 scavengelimit 时间,如果它们上面没有对象并且超过 scavengelimit 就会被释放。

在代码的更下方,您可以看到有一个跟踪选项。您可以使用它来查看,无论何时清道夫认为他需要清理:

$ GOGCTRACE=1 go run gc.go
gc1(1): 0+0+0 ms 0 -> 0 MB 423 -> 350 (424-74) objects 0 handoff
gc2(1): 0+0+0 ms 1 -> 0 MB 2664 -> 1437 (2880-1443) objects 0 handoff
gc3(1): 0+0+0 ms 1 -> 0 MB 4117 -> 2213 (5712-3499) objects 0 handoff
gc4(1): 0+0+0 ms 2 -> 1 MB 3128 -> 2257 (6761-4504) objects 0 handoff
gc5(1): 0+0+0 ms 2 -> 0 MB 8892 -> 2531 (13734-11203) objects 0 handoff
gc6(1): 0+0+0 ms 1 -> 1 MB 8715 -> 2689 (20173-17484) objects 0 handoff
gc7(1): 0+0+0 ms 2 -> 1 MB 5231 -> 2406 (22878-20472) objects 0 handoff
gc1(1): 0+0+0 ms 0 -> 0 MB 172 -> 137 (173-36) objects 0 handoff
getting memory
gc2(1): 0+0+0 ms 381 -> 381 MB 203 -> 202 (248-46) objects 0 handoff
returning memory
getting memory
returning memory

如您所见,在获取和返回之间没有执行 gc 调用。然而,如果你改变从 5 秒到 3 分钟的延迟(超过 forcegcperiod 的 2 分钟),对象被 gc 删除:

returning memory
scvg0: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB)
scvg0: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB)
scvg1: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB)
scvg1: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB)
gc9(1): 1+0+0 ms 1 -> 1 MB 4485 -> 2562 (26531-23969) objects 0 handoff
gc10(1): 1+0+0 ms 1 -> 1 MB 2563 -> 2561 (26532-23971) objects 0 handoff
scvg2: GC forced // forcegc (2 minutes) exceeded
scvg2: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB)
gc3(1): 0+0+0 ms 381 -> 381 MB 206 -> 206 (252-46) objects 0 handoff
scvg2: GC forced
scvg2: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB)
getting memory

内存仍未释放,但 GC 将内存区域标记为未使用。释放将在何时开始使用的跨度未使用且早于 limit。来自清道夫代码:

if(s->unusedsince != 0 && (now - s->unusedsince) > limit) {
// ...
runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
}

这种行为当然会随着时间的推移而改变,但我希望你现在能对物体有一点感觉被强行扔掉,如果没有。

正如zupa所指出的,释放对象可能不会将内存返回给操作系统,以此类推在某些系统中,您可能看不到内存使用量的变化。这似乎是计划 9 的情况和 Windows 根据 this thread on golang-nuts .

关于memory-management - Go 内存消耗管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14582471/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com