Golang和大内存块分配

时间:2017-06-01 01:24:18

标签: java go memory-management benchmarking

我有一个相当愚蠢的基准来测试内存分配的效率:

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秒内完成。

我在这里缺少什么?

1 个答案:

答案 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中的int32slice而不是array,它们不一样。 Go中的切片是类似结构的头文件,包含指向后备数组的指针(有关详细信息,请参阅reflect.SliceHeader),因此使用它们时会涉及隐式间接步骤。有关详细信息,请参阅Why have arrays in Go?也相关:Array vs Slice: accessing speed

最后一点:您的代码不会测量内存分配,因为这只是应用程序执行时间的一小部分。大多数(如99.99999%)的执行时间是将循环变量增加十亿次,并用十亿个元素填充数组。