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

时间:2016-05-31 16:40:45

标签: linux memory-management go out-of-memory

我尝试在Github中使用此包进行字符串匹配。我的字典是4 MB。在创建Trie时,我得到了fatal error: runtime: out of memory。我使用的是Ubuntu 14.04,内存为8 GB,Golang版本为1.4.2。

似乎错误来自第99行(现在)herem.trie = make([]node, max)

程序在此行停止。

这是错误:

fatal error: runtime: out of memory

runtime stack:
runtime.SysMap(0xc209cd0000, 0x3b1bc0000, 0x570a00, 0x5783f8)
    /usr/local/go/src/runtime/mem_linux.c:149 +0x98
runtime.MHeap_SysAlloc(0x57dae0, 0x3b1bc0000, 0x4296f2)
    /usr/local/go/src/runtime/malloc.c:284 +0x124
runtime.MHeap_Alloc(0x57dae0, 0x1d8dda, 0x10100000000, 0x8)
    /usr/local/go/src/runtime/mheap.c:240 +0x66

goroutine 1 [running]:
runtime.switchtoM()
    /usr/local/go/src/runtime/asm_amd64.s:198 fp=0xc208518a60 sp=0xc208518a58
runtime.mallocgc(0x3b1bb25f0, 0x4d7fc0, 0x0, 0xc20803c0d0)
    /usr/local/go/src/runtime/malloc.go:199 +0x9f3 fp=0xc208518b10 sp=0xc208518a60
runtime.newarray(0x4d7fc0, 0x3a164e, 0x1)
    /usr/local/go/src/runtime/malloc.go:365 +0xc1 fp=0xc208518b48 sp=0xc208518b10
runtime.makeslice(0x4a52a0, 0x3a164e, 0x3a164e, 0x0, 0x0, 0x0)
    /usr/local/go/src/runtime/slice.go:32 +0x15c fp=0xc208518b90 sp=0xc208518b48
github.com/mf/ahocorasick.(*Matcher).buildTrie(0xc2083c7e60, 0xc209860000, 0x26afb, 0x2f555)
    /home/go/ahocorasick/ahocorasick.go:104 +0x28b fp=0xc208518d90 sp=0xc208518b90
github.com/mf/ahocorasick.NewStringMatcher(0xc208bd0000, 0x26afb, 0x2d600, 0x8)
    /home/go/ahocorasick/ahocorasick.go:222 +0x34b fp=0xc208518ec0 sp=0xc208518d90
main.main()
    /home/go/seme/substrings.go:66 +0x257 fp=0xc208518f98 sp=0xc208518ec0
runtime.main()
    /usr/local/go/src/runtime/proc.go:63 +0xf3 fp=0xc208518fe0 sp=0xc208518f98
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:2232 +0x1 fp=0xc208518fe8 sp=0xc208518fe0
exit status 2

这是主要功能的内容(取自相同的repo:测试文件)

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 here
fmt.Println(precomputed.Match(bytes))

3 个答案:

答案 0 :(得分:8)

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

  • bool:1个字节
  • int:4个字节
  • uintptr:4个字节
  • [N]类型:N * sizeof(类型)
  • [] 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。

你应该检查一下你如何建立你的特里。在与Aho-Corasick算法相关的维基百科页面中,每个节点包含一个字符,因此最多有256个字符来自根,而不是4MB。

要使其正确的一些材料:http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf

答案 1 :(得分:3)

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

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

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

所以你应该尝试减少字典的大小。

答案 2 :(得分:0)

将资源限制设置为无限对我有用

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

也许会设置实际大小限制以更安全