为了账号安全,请及时绑定邮箱和手机立即绑定

分配大数据块的巨大 GC 性能问题

分配大数据块的巨大 GC 性能问题

Go
泛舟湖上清波郎朗 2021-09-09 21:19:05
我刚刚注意到,如果我在程序中分配了一个巨大的内存块。GC 会吃掉所有的程序时间。这是POC。https://gist.github.com/martende/252f403f0c17cb489de4func main() {    //////////////// !!!!!!!    /* If I uncomment 2 lines below programm runs fast */    nodesPool := make([]int, 300e6, 300e6)    _ = nodesPool    //////////////////////7    file, _ := os.Open("result.txt")    defer file.Close()    reader := bufio.NewReader(file)    var lastLinkIdx = 1 // Dont use first element use 0 as saver    cnt:=  0    totalB := 0    for {       l, err := reader.ReadString('\n')       if err == io.EOF {    fmt.Println("EOF")        break    }    cnt+=1          totalB+=len(l)    lines := strings.Split(l, ":")    nodeId,_ := strconv.Atoi(lines[0])    _ = nodeId    linkIdsStr  := strings.Split(lines[1], ",")    var ii = len(linkIdsStr)    _ = ii    /*      ... */}fmt.Println("pool ",cnt,totalB,lastLinkIdx)}我认为 GC 尝试以某种方式移动巨大的内存块,实际上是否可以从 GC 中分配内存但将 GC 留给所有其他库,因为即使 ReadLine 也需要它。这是使用内存块进行分析。Total: 1445 samples     428  29.6%  29.6%      722  50.0% runtime.sweepone     375  26.0%  55.6%      375  26.0% markroot     263  18.2%  73.8%      263  18.2% runtime.xadd     116   8.0%  81.8%      116   8.0% strings.Count      98   6.8%  88.6%      673  46.6% strings.genSplit      34   2.4%  90.9%       44   3.0% runtime.MSpan_Sweep      25   1.7%  92.7%      729  50.4% MCentral_Grow      17   1.2%  93.8%       19   1.3% syscall.Syscall       9   0.6%  94.5%        9   0.6% runtime.memclr       9   0.6%  95.1%        9   0.6% runtime.memmove这是没有内存块的分析。  98  27.0%  27.0%       98  27.0% strings.Count  93  25.6%  52.6%      228  62.8% strings.genSplit  45  12.4%  65.0%       45  12.4% scanblock  24   6.6%  71.6%       28   7.7% runtime.MSpan_Sweep  13   3.6%  75.2%       74  20.4% runtime.mallocgc  12   3.3%  78.5%       12   3.3% runtime.memclr   8   2.2%  80.7%        8   2.2% MHeap_ReclaimList   8   2.2%  82.9%       11   3.0% syscall.Syscall   6   1.7%  84.6%       44  12.1% MHeap_Reclaim   6   1.7%  86.2%        6   1.7% markonly
查看完整描述

1 回答

?
哈士奇WWW

TA贡献1799条经验 获得超6个赞

Go 团队的 Dmitry Vyukov说这是一个Go 运行时性能问题,你可以通过大量分配触发,作为一种解决方法,“你可以在大对象死后立即收集它,然后立即增加 GOGC .”


从广义上讲,GitHub 问题表明运行时会创建大量内存管理结构(跨度),然后它会无限期地保留这些结构,并且必须在每次 GC 上进行扫描。根据问题标签,Go 1.5 的目标是修复。


他的解决方法示例是:


package main


import (

    "runtime"

    "runtime/debug"

)


var x = make([]byte, 1<<20)

var y []byte

var z []byte


func main() {

    y = make([]byte, 1<<30)

    y = nil

    runtime.GC()

    debug.SetGCPercent(1000)

    for i := 0; i < 1e6; i++ {

        z = make([]byte, 8192)

    }

}

(一些评论是关于一个完全不同的答案和代码示例,重点是避免我已经编辑掉的分配。没有办法“告诉”StackOverflow 这是一个新答案,所以它们仍然存在。)


查看完整回答
反对 回复 2021-09-09
  • 1 回答
  • 0 关注
  • 177 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信