use make or not

假如要获取一组一定长度的整形数组,是使用固定长度初始化数组的性能高还是使用 make() 然后不断追加 (append) 产生数组的性能高呢?
如果你选了其中一个,都不对。为什么?看数据吧
在这里分别设置获取不同数量级 lenFix 长度的数组为例:

const lenFix = 10 000 //fix is better than make

~/golang/src/demo/10things/pack  ᐅ go test -bench=. -benchmem -blockprofile p.out -coverprofile cover.out -memprofile mem.out
testing: warning: no tests to run
PASS
BenchmarkGroupedGlobalsMake	  30000	    57851 ns/op	  81920 B/op	      1 allocs/op
BenchmarkGroupedGlobalsFix	 100000	    24426 ns/op	      0 B/op	      0 allocs/op
coverage: 27.6% of statements
ok  	demo/10things/pack	5.113s

const lenFix = 100 000 //equal

~/golang/src/demo/10things/pack  ᐅ go test -bench=. -benchmem -blockprofile p.out -coverprofile cover.out -memprofile mem.out
testing: warning: no tests to run
PASS
BenchmarkGroupedGlobalsMake	   5000	   261474 ns/op	 802816 B/op	      1 allocs/op
BenchmarkGroupedGlobalsFix	   5000	   278088 ns/op	      0 B/op	      0 allocs/op
coverage: 27.6% of statements
ok  	demo/10things/pack	2.863s

const lenFix = 1000 000 //fix is slow than make nearly haf

~/golang/src/demo/10things/pack  ᐅ go test -bench=. -benchmem -blockprofile p.out -coverprofile cover.out -memprofile mem.out
testing: warning: no tests to run
PASS
BenchmarkGroupedGlobalsMake	    500	  3113893 ns/op	8003584 B/op	      1 allocs/op
BenchmarkGroupedGlobalsFix	    300	  4785933 ns/op	      0 B/op	      0 allocs/op
coverage: 27.6% of statements
ok  	demo/10things/pack	3.927s

const lenFix = 10 000 000 //make is better than fix

~/golang/src/demo/10things/pack  ᐅ go test -bench=. -benchmem -blockprofile p.out -coverprofile cover.out -memprofile mem.out
testing: warning: no tests to run
PASS
BenchmarkGroupedGlobalsMake	     50	 28069067 ns/op	80003072 B/op	      1 allocs/op
BenchmarkGroupedGlobalsFix	     20	 66387139 ns/op	80003072 B/op	      1 allocs/op
coverage: 27.6% of statements
ok  	demo/10things/pack	4.682s

const lenFix = 100 000 000 //fix occurs error but make runs normally

~/golang/src/demo/10things/pack  ᐅ go test -bench=. -benchmem -blockprofile p.out -coverprofile cover.out -memprofile mem.out
testing: warning: no tests to run
PASS
BenchmarkGroupedGlobalsMake	      2	681053704 ns/op	800006144 B/op	      1 allocs/op
BenchmarkGroupedGlobalsFix	runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

可以看在大概100 000个长度之前,使用固定长度类型的数组所需要的时间是比使用 make 方法获取的数组的时间要短,但一超过这个长度后则相反。固定长度类型的数组初始化不需要进行内存的申请操作,减缓 GC 的触发频率,而 make 则必须要进行一次内存的 alloc 操作, 但是 make 在实际应用中会么比较灵活一点,毕竟可以方便的进行数组增长(其实背后也是复制原来的数据到新申请的数组中), 还有,固定数组的初始化有长度限制,超过 stack 所允许的容量时就会现fatal error: stack overflow错误,所以在实际开发中还是使用 make 更为安全可靠。

—update—
原来 make() 是在 heap 中创建,而直接用 [count]int 使用的是 stack 的空间,golang.1.4.x 所允许的最大 stack 为 2MB(1<<20), 该值对应于 runtime/stack.c 中的 runtime·maxstacksize

2015-09-04