nakamura244 blog

所属団体とは関係なく、個人的なblog

golangにおけるcopy-on-write (COW)

結論

ない?!と思った

検証

雑にこんなコードがある

package main

import (
    "fmt"
    "runtime"
)

var mem runtime.MemStats

func printMem() {
    runtime.ReadMemStats(&mem)
    fmt.Printf("%d byte \n", mem.Alloc)
}

func main()  {

    v := [9999999]int{}


    var i int
    for i = 0; i < 9999999; i++ {
        v[i] = i
    }
    printMem()

    c := v
    printMem()

    fmt.Println(v[0])
    fmt.Println(c[0])
}

実行すると

- go run test.go

80,115,344 byte 
160,122,064 byte 

すでに変数に代入した段階で実際に値がコピーされている為に利用メモリが増えている

例えばcopy-on-write (COW)の最適化が働いている場合は

例えばPHPとかで同じように下記のテストコードがある

<?php
$a = array_fill(0, 999, "aaa");
echo number_format(memory_get_usage()) . "byte \n";
$b = $a;             // 配列を代入
echo number_format(memory_get_usage()) . "byte \n";

実行すると

- php test.php

323,960byte
324,096byte

誤差は多少あれど、変数に代入しただけでは利用メモリは増えない。

今度は変数に代入した先で値を変えて(writeを発生)やる

<?php
$a = array_fill(0, 999, "aaa");
echo number_format(memory_get_usage()) . "byte \n";
$b = $a;             // 配列を代入
echo number_format(memory_get_usage()) . "byte \n";
$b[1] = 0;           // 代入先の配列を変更
echo number_format(memory_get_usage()) . "byte \n";

実行すると

- php test.php

324,536byte
324,672byte
421,000byte

writeが発生したため、実際に値のコピーをしてからwriteした為、メモリ利用量は増えた。

なので

golangにおいてはcopy-on-writeで裏で最適化してくれはしないようですね。なんとなく頭に入れながらコーディングをしていこうかと思います。

なんでないのだろうか?とか、もっと別の理由であえてないとか、深堀してみたいけど帰ってこれなくなりそうなので一旦ここまでにしとこうかと思う