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

Golang:致命错误:运行时:内存不足

Golang:致命错误:运行时:内存不足

Go
呼啦一阵风 2022-01-17 10:16:52
我试图在Github中使用这个包进行字符串匹配。我的字典是 4 MB。创建 Trie 时,我得到了fatal error: runtime: out of memory. 我正在使用具有 8 GB RAM 和 Golang 版本 1.4.2 的 Ubuntu 14.04。似乎错误来自第 99 行(现在):m.trie = make([]node, max)程序停在这一行。这是错误:fatal error: runtime: out of memoryruntime stack:runtime.SysMap(0xc209cd0000, 0x3b1bc0000, 0x570a00, 0x5783f8)    /usr/local/go/src/runtime/mem_linux.c:149 +0x98runtime.MHeap_SysAlloc(0x57dae0, 0x3b1bc0000, 0x4296f2)    /usr/local/go/src/runtime/malloc.c:284 +0x124runtime.MHeap_Alloc(0x57dae0, 0x1d8dda, 0x10100000000, 0x8)    /usr/local/go/src/runtime/mheap.c:240 +0x66goroutine 1 [running]:runtime.switchtoM()    /usr/local/go/src/runtime/asm_amd64.s:198 fp=0xc208518a60 sp=0xc208518a58runtime.mallocgc(0x3b1bb25f0, 0x4d7fc0, 0x0, 0xc20803c0d0)    /usr/local/go/src/runtime/malloc.go:199 +0x9f3 fp=0xc208518b10 sp=0xc208518a60runtime.newarray(0x4d7fc0, 0x3a164e, 0x1)    /usr/local/go/src/runtime/malloc.go:365 +0xc1 fp=0xc208518b48 sp=0xc208518b10runtime.makeslice(0x4a52a0, 0x3a164e, 0x3a164e, 0x0, 0x0, 0x0)    /usr/local/go/src/runtime/slice.go:32 +0x15c fp=0xc208518b90 sp=0xc208518b48github.com/mf/ahocorasick.(*Matcher).buildTrie(0xc2083c7e60, 0xc209860000, 0x26afb, 0x2f555)    /home/go/ahocorasick/ahocorasick.go:104 +0x28b fp=0xc208518d90 sp=0xc208518b90github.com/mf/ahocorasick.NewStringMatcher(0xc208bd0000, 0x26afb, 0x2d600, 0x8)    /home/go/ahocorasick/ahocorasick.go:222 +0x34b fp=0xc208518ec0 sp=0xc208518d90main.main()这是 main 函数的内容(取自同一个 repo:test 文件)var dictionary = InitDictionary()   var bytes = []byte(""Partial invoice (€100,000, so roughly 40%) for the consignment C27655 we shipped on 15th August to London from the Make Believe Town depot. INV2345 is for the balance.. Customer contact (Sigourney) says they will pay this on the usual credit terms (30 days).")   var precomputed = ahocorasick.NewStringMatcher(dictionary)// line 66 herefmt.Println(precomputed.Match(bytes))
查看完整描述

3 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

您的结构在内存方面非常低效,让我们看看内部结构。但在此之前,快速提醒一些 go 类型所需的空间:

  • 布尔值:1 个字节

  • 整数:4 字节

  • uintptr:4 字节

  • [N]类型:N*sizeof(type)

  • []type: 12 + len(slice)*sizeof(type)

现在,让我们看看你的结构:

type node struct {

    root bool        // 1 byte

    b []byte         // 12 + len(slice)*1

    output bool      // 1 byte

    index int        // 4 bytes

    counter int      // 4 bytes

    child [256]*node // 256*4 = 1024 bytes

    fails [256]*node // 256*4 = 1024 bytes

    suffix *node     // 4 bytes

    fail *node       // 4 bytes

}

好的,你应该猜到这里发生了什么:每个节点的重量都超过 2KB,这是巨大的!最后,我们将查看用于初始化 trie 的代码:


func (m *Matcher) buildTrie(dictionary [][]byte) {

    max := 1

    for _, blice := range dictionary {

        max += len(blice)

    }

    m.trie = make([]node, max)


    // ...

}

你说你的字典是 4 MB。如果总共是 4MB,那么就意味着在 for 循环结束时,max = 4MB. 它包含 4 MB 不同的单词,然后max = 4MB*avg(word_length).


我们将采用第一个场景,最好的一个。您正在初始化一个 4M 节点的切片,每个节点使用 2KB。是的,这需要一个不错的 8GB。


您应该查看如何构建您的 trie。从与 Aho-Corasick 算法相关的维基百科页面中,每个节点包含一个字符,因此从根开始最多有 256 个字符,而不是 4MB。


一些使其正确的材料:https ://web.archive.org/web/20160315124629/http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf


查看完整回答
反对 回复 2022-01-17
?
阿晨1998

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

node类型的内存大小为2084字节。我写了一个小程序来演示内存使用情况:https: //play.golang.org/p/szm7AirsDB

如您所见,三个字符串(大小为 11(+1) 个字节)dictionary := []string{"fizz", "buzz", "123"}需要 24 MB 内存。

如果您的字典有 4 MB 的长度,您将需要大约4000 * 2084 = 8.1 GB内存。

因此,您应该尝试减小字典的大小。


查看完整回答
反对 回复 2022-01-17
?
catspeake

TA贡献1111条经验 获得超0个赞

将资源限制设置为无限制为我工作

如果ulimit -a返回 0 运行ulimit -c unlimited

也许设置一个真正的大小限制更安全


查看完整回答
反对 回复 2022-01-17
  • 3 回答
  • 0 关注
  • 599 浏览
慕课专栏
更多

添加回答

举报

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