いろいろ備忘録日記

主に .NET とか Go とか Python絡みのメモを公開しています。

Goメモ-59 (現在のメモリ使用量を取得, runtime.MemStats)

概要

メモリ使用量を取得するやり方を調べていたので、忘れないうちにメモメモ。

大抵どの言語でもあるものなんですが、Goの場合は runtime.ReadMemStats(*runtime.MemStats) で取得できるみたいですね。

以下、ちょっとしたメモ書きサンプルです。

サンプル

package runtime_

import (
    "context"
    "fmt"
    "github.com/devlights/try-golang/lib/output"
    "runtime"
    "sync"
    "time"
)

// RuntimeMemoryStats は、runtime.MemoryStats() のサンプルです.
//
// REFERENCES::
//   - https://golangcode.com/print-the-current-memory-usage/
func RuntimeMemoryStats() error {
    var (
        rootCtx         = context.Background()
        mainCtx, cancel = context.WithCancel(rootCtx)
        wg              = &sync.WaitGroup{}
    )

    // 初期の状態を表示
    runtime.GC()
    printMemoryStats("init")

    // ---------------------------------------
    // データを500ミリ秒毎に増やしていく処理
    // ---------------------------------------
    wg.Add(1)
    go func(ctx context.Context, wg *sync.WaitGroup) {
        var (
            tick  = time.Tick(500 * time.Millisecond)
            count = 0
            items = make([][]byte, 0, 5)
        )

        defer wg.Done()

        for {
            select {
            case <-ctx.Done():
                return
            case _ = <-tick:
                count++
                data := make([]byte, 0, 1024*1024)
                items = append(items, data)

                // output.Stderrf("[append]", "count=%d\ttick=%v\n", count, t)
            }
        }
    }(mainCtx, wg)

    // ---------------------------------------
    // 現在のメモリ量を2000ミリ秒毎に出力する処理
    // ---------------------------------------
    wg.Add(1)
    go func(ctx context.Context, wg *sync.WaitGroup) {
        var (
            tick  = time.Tick(2000 * time.Millisecond)
            count = 0
        )

        defer wg.Done()

        for {
            select {
            case <-ctx.Done():
                return
            case <-tick:
                count++
                printMemoryStats(fmt.Sprintf("(%d)", count))
            }
        }
    }(mainCtx, wg)

    // 10秒したら終わり
    select {
    case <-time.After(10 * time.Second):
        cancel()
        wg.Wait()
    }

    // 最後の状態を表示
    printMemoryStats("latest")

    // GC後の状態を表示
    runtime.GC()
    printMemoryStats("after runtime.GC()")

    return nil
}

func printMemoryStats(prefix string) {
    // --------------------------------------------------------
    // runtime.MemoryStats() から、現在の割当メモリ量などが取得できる.
    //
    // まず、データの受け皿となる runtime.MemStats を初期化し
    // runtime.ReadMemStats(*runtime.MemStats) を呼び出して
    // 取得する.
    // --------------------------------------------------------
    var (
        ms runtime.MemStats
    )

    output.Stdoutl(prefix, "----------------------------")
    runtime.ReadMemStats(&ms)

    // Alloc は、現在ヒープに割り当てられているメモリ
    // HeapAlloc と同じ.
    output.Stdoutl("Alloc", toKb(ms.Alloc))
    output.Stdoutl("HeapAlloc", toKb(ms.HeapAlloc))

    // TotalAlloc は、ヒープに割り当てられたメモリ量の累積
    // Allocと違い、こちらは増えていくが減ることはない
    output.Stdoutl("TotalAlloc", toKb(ms.TotalAlloc))

    // HeapObjects は、ヒープに割り当てられているオブジェクトの数
    output.Stdoutl("HeapObjects", toKb(ms.HeapObjects))

    // Sys は、OSから割り当てられたメモリの合計量
    output.Stdoutl("Sys", toKb(ms.Sys))

    // NumGC は、実施されたGCの回数
    output.Stdoutl("NumGC", ms.NumGC)
}

func toKb(bytes uint64) uint64 {
    return bytes / 1024
}

//noinspection GoUnusedFunction
func toMb(bytes uint64) uint64 {
    return toKb(bytes) / 1024
}

try-golang/runtime_memorystats.go at master · devlights/try-golang · GitHub

実行すると以下のようになります。

$ make run
ENTER EXAMPLE NAME: runtime_mem
[Name] "runtime_memorystats"
init                 ----------------------------
Alloc                190
HeapAlloc            190
TotalAlloc           241
HeapObjects          1
Sys                  4932
NumGC                1
(1)                  ----------------------------
Alloc                3269
HeapAlloc            3269
TotalAlloc           3320
HeapObjects          1
Sys                  10822
NumGC                1
(2)                  ----------------------------
Alloc                8390
HeapAlloc            8390
TotalAlloc           8444
HeapObjects          1
Sys                  15114
NumGC                3
(3)                  ----------------------------
Alloc                11463
HeapAlloc            11463
TotalAlloc           11518
HeapObjects          1
Sys                  19342
NumGC                3
(4)                  ----------------------------
Alloc                16584
HeapAlloc            16584
TotalAlloc           16638
HeapObjects          1
Sys                  23570
NumGC                3
(5)                  ----------------------------
Alloc                20679
HeapAlloc            20679
TotalAlloc           20736
HeapObjects          1
Sys                  27798
NumGC                4
latest               ----------------------------
Alloc                20679
HeapAlloc            20679
TotalAlloc           20736
HeapObjects          1
Sys                  27798
NumGC                4
after runtime.GC()   ----------------------------
Alloc                197
HeapAlloc            197
TotalAlloc           20738
HeapObjects          1
Sys                  27798
NumGC                5

参考

golangcode.com

golang.org


過去の記事については、以下のページからご参照下さい。

  • いろいろ備忘録日記まとめ

devlights.github.io

サンプルコードは、以下の場所で公開しています。

  • いろいろ備忘録日記サンプルソース置き場

github.com

github.com

github.com