我有一个相当愚蠢的基准来测试内存分配的效率:
package main
import (
"time"
"fmt"
)
func main() {
size := 1024 * 1024 * 1024
t := time.Now()
for j := 0; j < 100; j += 1 {
a := make([]int, size)
for i := 0; i < size; i += 1 {
a[i] = i
}
a = nil
}
t1 := time.Now()
fmt.Printf("Duration: %1d", t1.Sub(t).Seconds())
}
Mac Pro上需要大约2-3分钟,内存为16GB,内存使用率一致为5-8 GB。
Java中非常相似的代码占用3 GB内存,并在30秒内完成。
我在这里缺少什么?
答案 0 :(得分:3)
我在这里缺少什么?
在Java中,int
类型的大小固定为4个字节。在Go int
中是一种体系结构相关类型,在32位体系结构上它是32位(4字节),在64位体系结构上它是64位(8字节)。
很可能你是在64位拱门上运行它。这意味着您分配的Go切片/阵列的大小为8 * 1 GB = 8 GB,而在Java中,它只有4 * 1 GB = 4 GB。
此外,由于您在循环中使用int
,因此Java只需递增并设置4字节值,而在Go中,您需要递增并设置8字节值(类型{{1 }}和i
将是j
)。
将您的Go代码更改为使用int
,然后再试一次。
另请注意,您的内存使用量测量存在缺陷,因为Java中的数组大小为4 GB,Go中为8 GB,因此Java中的3 GB和Go中的5-8 GB不是总内存使用量!< / p>
另请注意,Go中的int32
是slice而不是array,它们不一样。 Go中的切片是类似结构的头文件,包含指向后备数组的指针(有关详细信息,请参阅reflect.SliceHeader
),因此使用它们时会涉及隐式间接步骤。有关详细信息,请参阅Why have arrays in Go?也相关:Array vs Slice: accessing speed
最后一点:您的代码不会测量内存分配,因为这只是应用程序执行时间的一小部分。大多数(如99.99999%)的执行时间是将循环变量增加十亿次,并用十亿个元素填充数组。