如何减少内存使用量?

时间:2017-03-17 15:35:23

标签: memory go garbage-collection

我有一个使用太多内存并因此被杀的go程序,所以我想尝试保持内存使用率下降。这是我正在做的简化愚蠢版本,揭示了这个问题:

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "os/exec"
    "runtime"
    "runtime/debug"
    "strconv"
    "time"
)

func main() {
    source := "/tmp/1G.source"
    repeats, _ := strconv.Atoi(os.Args[1])
    m := &runtime.MemStats{}

    err := exec.Command("dd", "if=/dev/zero", "of="+source, "bs=1073741824", "count=1").Run()
    if err != nil {
        log.Fatalf("failed to create 1GB file: %s\n", err)
    }
    fmt.Printf("created 1GB source file, %s\n", memory_usage(m))

    // read it multiple times
    switch os.Args[2] {
    case "1":
        fmt.Println("re-using a byte slice and emptying it each time")
        // var data []byte
        for i := 1; i <= repeats; i++ {
            data, _ := ioutil.ReadFile(source)
            if len(data) > 0 { // just so we use data
                data = nil
            }
            fmt.Printf("did read %d, %s\n", i, memory_usage(m))
        }
    case "2":
        fmt.Println("ignoring the return value entirely")
        for i := 1; i <= repeats; i++ {
            ioutil.ReadFile(source)
            fmt.Printf("did read %d, %s\n", i, memory_usage(m))
        }
    case "3":
        fmt.Println("ignoring the return value entirely, forcing memory freeing")
        for i := 1; i <= repeats; i++ {
            ioutil.ReadFile(source)
            debug.FreeOSMemory()
            fmt.Printf("did read %d, %s\n", i, memory_usage(m))
        }
    }

    // wait incase garbage collection needs time to do something
    <-time.After(5 * time.Second)

    fmt.Printf("all done, %s\n", memory_usage(m))

    os.Exit(0)
}

func memory_usage(m *runtime.MemStats) string {
    runtime.ReadMemStats(m)
    return fmt.Sprintf("system memory: %dMB; heap alloc: %dMB; heap idle-released: %dMB", int((m.Sys/1024)/1024), int((m.HeapAlloc/1024)/1024), int(((m.HeapIdle-m.HeapReleased)/1024)/1024))
}

如果我用main 7 2打电话给我:

created 1GB source file, system memory: 2MB; heap alloc: 0MB; heap idle-released: 1MB
ignoring the return value entirely
did read 1, system memory: 4233MB; heap alloc: 3072MB; heap idle-released: 1024MB
did read 2, system memory: 4233MB; heap alloc: 3072MB; heap idle-released: 1024MB
did read 3, system memory: 4233MB; heap alloc: 3072MB; heap idle-released: 1024MB
did read 4, system memory: 4233MB; heap alloc: 3072MB; heap idle-released: 1023MB
did read 5, system memory: 6347MB; heap alloc: 3584MB; heap idle-released: 2559MB
did read 6, system memory: 6347MB; heap alloc: 3072MB; heap idle-released: 3071MB
did read 7, system memory: 6347MB; heap alloc: 3072MB; heap idle-released: 3071MB
all done, system memory: 6347MB; heap alloc: 3072MB; heap idle-released: 3071MB

也许偏离主题,但是预计读取1GB文件会导致4GB的系统内存使用量?

无论如何,理想情况下我希望无限数量的相同循环使用〜恒定的内存量,而不是从4GB增加到6GB。

所以我认为强制释放内存会有所帮助,但main 7 3给出了:

created 1GB source file, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
ignoring the return value entirely, forcing memory freeing
did read 1, system memory: 4237MB; heap alloc: 0MB; heap idle-released: 0MB
did read 2, system memory: 4237MB; heap alloc: 0MB; heap idle-released: 0MB
did read 3, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB
did read 4, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB
did read 5, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB
did read 6, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB
did read 7, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB
all done, system memory: 6351MB; heap alloc: 0MB; heap idle-released: 0MB

如何保持所有循环的内存使用率下降?

根据评论中的建议,我尝试了一个新案例:

case "4":
    fmt.Println("doing a streaming read")
    b := make([]byte, 10000, 10000)
    for i := 1; i <= repeats; i++ {
        f, _ := os.Open(source)
        r := bufio.NewReader(f)
        for {
            _, err := r.Read(b)
            if err != nil {
                break
            }
        }
        fmt.Printf("did read %d, %s\n", i, memory_usage(m))
    }
}

但是我仍然会通过循环次数来增加内存使用量:

created 1GB source file, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
doing a streaming read
did read 1, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
did read 2, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
did read 3, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
did read 4, system memory: 1MB; heap alloc: 0MB; heap idle-released: 0MB
did read 5, system memory: 2MB; heap alloc: 0MB; heap idle-released: 0MB
did read 6, system memory: 2MB; heap alloc: 0MB; heap idle-released: 0MB
did read 7, system memory: 2MB; heap alloc: 0MB; heap idle-released: 0MB
all done, system memory: 2MB; heap alloc: 0MB; heap idle-released: 0MB

概括一下这个问题,当你在循环中使用第三方功能(即,你无法控制他们如何在自己内部使用内存)时,并且每个人都做同样的事情。在循环中的时间,是否有任何方法可以强制Go重新使用已经分配的内存而不是从操作系统请求更多内存?

0 个答案:

没有答案