douhuiwan5141 2014-09-26 15:36
浏览 96
已采纳

转到:空花括号对数组初始化内存分配的影响

I was playing with different ways to initialise/declare arrays in golang. I got different behaviours/results.

go version go1.3 darwin/amd64

version 1:

func main() {
    a := [100000000]int64{}
    var i int64
    for i = 0; i < 100000000; i++ {
        a[i] = i
    }
}

Produces a 763MB binary. It crashes after a few seconds when I run it with this message.

runtime: goroutine stack exceeds 1000000000-byte limit

fatal error: stack overflow

version 2:

func main() {
    var a [100000000]int64
    var i int64
    for i = 0; i < 100000000; i++ {
        a[i] = i
    }
}

Produces a 456KB binary. It runs in less than one second.

Question:

Can anybody help me understand why those differences (and other I may have missed) are there? Thanks!

edit:

Running times:

I built the two different snippets and run the compiled versions, so the compilation time wasn't added. The first time I run version1 is extremely slow in comparison though. Here is the output.

go build version1.go
go build version2.go

These are the execution outputs

version 1

first run

time ./version1
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x2fb42a8e)
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/panic.c:520 +0x69
runtime.newstack()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/stack.c:770 +0x486
runtime.morestack()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/asm_amd64.s:228 +0x61

goroutine 16 [stack growth]:
main.main()
    /Users/ec/repo/offers/lol/version1.go:3 fp=0x2b7b85f50 sp=0x2b7b85f48
runtime.main()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:247 +0x11a fp=0x2b7b85fa8 sp=0x2b7b85f50
runtime.goexit()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:1445 fp=0x2b7b85fb0 sp=0x2b7b85fa8
created by _rt0_go
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/asm_amd64.s:97 +0x120

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/mheap.c:507
runtime.goexit()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:1445
./version1  0.00s user 0.10s system 1% cpu 7.799 total

second run

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

runtime stack:
runtime.throw(0x2fb42a8e)
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/panic.c:520 +0x69
runtime.newstack()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/stack.c:770 +0x486
runtime.morestack()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/asm_amd64.s:228 +0x61

goroutine 16 [stack growth]:
main.main()
    /Users/ec/repo/offers/lol/version1.go:3 fp=0x2b7b85f50 sp=0x2b7b85f48
runtime.main()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:247 +0x11a fp=0x2b7b85fa8 sp=0x2b7b85f50
runtime.goexit()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:1445 fp=0x2b7b85fb0 sp=0x2b7b85fa8
created by _rt0_go
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/asm_amd64.s:97 +0x120

goroutine 17 [runnable]:
runtime.MHeap_Scavenger()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/mheap.c:507
runtime.goexit()
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/proc.c:1445
./version1  0.00s user 0.10s system 98% cpu 0.102 total

version 2

first run

time ./version2
./version2  0.16s user 0.26s system 99% cpu 0.429 total

second run

time ./version2
./version2  0.17s user 0.25s system 97% cpu 0.421 total
  • 写回答

2条回答 默认 最新

  • dongtaihui5131 2014-09-26 15:41
    关注

    In Version 1, you're declaring a literal array of [100000000]int64{} which the compiler immediately allocates.

    Version 2, you're only declaring the type of a as [100000000]int64.

    When you only have a variable declaration, the contents aren't known at that point during compilation. In version 2, the compiler knows that a is of type [100000000]int64, but the memory isn't allocated until runtime.

    When you use a literal, that exact memory representation is written into the binary. It works the same as if you declared a string literal vs a variable of type string; the string literal will be written in place, while a variable declaration is only a placeholder.

    Even though the current compiler (go 1.3) allows a to escape to the heap, the literal data is expected to live in the stack frame. You can see this in the assembly output (frame size is 800000016):

    TEXT    "".func1+0(SB),$800000016-0
    

    If you actually need a larger literal than what can fit in the stack, you can place it in a global variable. The following executes just fine:

    var a = [100000000]int64{1}
    
    func func1() {
        var i int64
        for i = 0; i < 100000000; i++ {
            a[i] = i
        }
    }
    

    I did have to initialize at least one value in a here, because it seems that the compiler can elide this literal, if it's equal to the zero value.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 MATLAB动图的问题
  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名