2016-03-21 9 views
5

GOでのメモリ割り当てのパフォーマンスをチェックしているうちに面白いことに遭遇しました。golangスライス割り当ての性能

package main 

import (
     "fmt" 
     "time" 
    ) 

func main(){ 
    const alloc int = 65536 
    now := time.Now() 
    loop := 50000 
    for i := 0; i<loop;i++{ 
     sl := make([]byte, alloc) 
     i += len(sl) * 0 
    } 
    elpased := time.Since(now) 
    fmt.Printf("took %s to allocate %d bytes %d times", elpased, alloc, loop) 
} 

私は行くバージョン1.6 64ビット(32ビットでも同じ結果)と16ギガバイトのRAM(WINDOWS 10上)のallocは65536(正確に64K)であるとき はそれを実行してコアi7の2600でこれを実行しています30秒間(!!!!)。 allocが65535の場合、それは約200msかかります。 誰かが私にこれを説明できますか? コアi7-920 @ 3.8GHZで同じコードを自宅で試しましたが、同じ結果は表示されませんでした(どちらも約200msでした)。誰でも何が起こっているのか考えていますか?

+1

さらに多くのバリエーションを追加するには、Windows 7(Go 1.6,64ビット)でコードを試しても、 'alloc 'が65536または65535であれば17秒かかります。 – icza

+0

私は割り振り内部の専門家ではありませんが、65536バイトのスライスを割り当てることは実際にはその2つの整数( 'len'と' cap'カウンター)を割り当てているので、実際は64KB以上です。 – Elwinar

+2

問題に情報を追加するために、私はArchlinux(i7-4720HQ @ 2.60GHz)でコードを実行しました。一貫して〜600msかかります。長い時間がかかるセットアップでは、プロファイリングツールを使用するようにしてください。あなたがすでにそれを知らないなら、それを学ぶのは良い事実です。 – Elwinar

答えて

4

GOGC = offに設定するとパフォーマンスが向上します(100ms未満まで)。どうして? がescape analysisである。 go build -gcflags -mでビルドすると、ヒープにエスケープされた割り当てがすべて出力されます。実際にはマシンとGOコンパイラのバージョンに依存しますが、コンパイラが割り振りをヒープに移動する必要があると判断した場合、2つのことを意味します。 1.割り振りに時間がかかります(スタック上の「割り当て」は1CPU命令です)。 2. GCはそのメモリを後でクリーンアップする必要があります。私のマシンでは、より多くのCPU時間を要します。、65536バイトの割り当てはヒープにエスケープされ、65535は割り当てられません。 これは、1バイトがプロセス全体を200msから30sに変更した理由です。 Amazing ..