いろいろ備忘録日記

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

Goメモ-415 (ヒープメモリの統計情報を取得, runtime/metrics)

関連記事

GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ

概要

以下、自分用のメモです。忘れないようにここにメモメモ。。。

Go 1.16 から、runtime/metrics というパッケージが追加されていたのを最近知りました。

Go 1.16 リリースノート には、以下のように記載されています。

The new runtime/metrics package introduces a stable interface for reading implementation-defined metrics from the Go runtime. It supersedes existing functions like runtime.ReadMemStats and debug.GCStats and is significantly more general and efficient. See the package documentation for more details.

(新しいruntime/metricsパッケージは、Goランタイムから実装定義のメトリクスを読み取るための安定したインターフェイスを導入します。これはruntime.ReadMemStatsやdebug.GCStatsのような既存の関数に取って代わり、より一般的で効率的です。)

なるほど。。とりあえず、呼び出してみたサンプルを未来の自分のために貼り付けておきます。

サンプル

package metricsop

import (
    "runtime"
    "runtime/metrics"

    "github.com/devlights/gomy/output"
)

// Heap は、runtime/metrics を利用してヒープメモリ関連の情報を取得するサンプルです.
//
// # REFERENCES
//   - https://pkg.go.dev/runtime/metrics@latest
func Heap() error {
    var (
        items = []string{
            "/memory/classes/heap/free:bytes",     // 完全に空いていて、システムに戻す資格があるが、戻されていないメモリ
            "/memory/classes/heap/objects:bytes",  // ガベージコレクタによってまだ解放されていないメモリ
            "/memory/classes/heap/released:bytes", // 完全に解放され、システムに戻されたメモリ
            "/memory/classes/heap/stacks:bytes",   // スタック領域として予約されている、ヒープから割り当てられたメモリ、現在使用中であるか否かを問わない
            "/memory/classes/heap/unused:bytes",   // ヒープオブジェクトのために予約されているが、現在ヒープオブジェクトを保持するために使われていないメモリ
            "/gc/heap/allocs:bytes",               // アプリケーションによってヒープに割り当てられたメモリの累計。
            "/gc/heap/allocs:objects",             // アプリケーションによって引き起こされたヒープ割り当ての累積カウント
            "/gc/heap/frees:bytes",                // ガベージコレクタによって解放されたヒープメモリの累計
            "/gc/heap/frees:objects",              // ストレージがガベージコレクタによって解放されたヒープ割り当ての累積カウント
            "/gc/heap/goal:bytes",                 // GCサイクル終了時のヒープサイズ目標
            "/gc/heap/live:bytes",                 // 前回のGCでマークされたライブオブジェクトが占有するヒープメモリ
            "/gc/heap/objects:objects",            // ヒープメモリを占有しているオブジェクトの数
        }
        samples = make([]metrics.Sample, len(items))
        bigdata = make([]byte, 1<<28)
    )

    for i, name := range items {
        samples[i].Name = name
    }

    runtime.GC()
    metrics.Read(samples)
    for _, s := range samples {
        output.Stdoutl("[Name ]", s.Name)

        switch s.Value.Kind() {
        case metrics.KindUint64:
            output.Stdoutf("[Value]", "%v\n", s.Value.Uint64())
        case metrics.KindFloat64:
            output.Stdoutf("[Value]", "%v\n", s.Value.Float64())
        case metrics.KindFloat64Histogram:
            output.Stdoutf("[Value]", "Bucket Count: %d\n", len(s.Value.Float64Histogram().Buckets)-2)
        default:
            output.Stdoutl("[Value]", "INVALID")
        }

        output.StdoutHr()
    }

    output.Stdoutl("[Buffer]", len(bigdata))

    return nil
}

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

       $ task
        task: [build] go build .
        task: [run] ./try-golang -onetime

        ENTER EXAMPLE NAME: metrics_heap

        [Name] "metrics_heap"
        [Name ]              /memory/classes/heap/free:bytes
        [Value]              237232128
        --------------------------------------------------
        [Name ]              /memory/classes/heap/objects:bytes
        [Value]              395616
        --------------------------------------------------
        [Name ]              /memory/classes/heap/released:bytes
        [Value]              33882112
        --------------------------------------------------
        [Name ]              /memory/classes/heap/stacks:bytes
        [Value]              425984
        --------------------------------------------------
        [Name ]              /memory/classes/heap/unused:bytes
        [Value]              693920
        --------------------------------------------------
        [Name ]              /gc/heap/allocs:bytes
        [Value]              268953040
        --------------------------------------------------
        [Name ]              /gc/heap/allocs:objects
        [Value]              1668
        --------------------------------------------------
        [Name ]              /gc/heap/frees:bytes
        [Value]              268557424
        --------------------------------------------------
        [Name ]              /gc/heap/frees:objects
        [Value]              459
        --------------------------------------------------
        [Name ]              /gc/heap/goal:bytes
        [Value]              4194304
        --------------------------------------------------
        [Name ]              /gc/heap/live:bytes
        [Value]              395904
        --------------------------------------------------
        [Name ]              /gc/heap/objects:objects
        [Value]              1209
        --------------------------------------------------
        [Buffer]             268435456


        [Elapsed] 4.183119ms

確かにいろいろ取得出来ていますね。

取得するためのキー名を間違えて指定した場合はエラーとかにはならずに値が返ってきて、Kindの値が0となっています。

参考情報

metrics package - runtime/metrics - Go Packages

Goのおすすめ書籍


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

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