以下の内容はhttps://devlights.hatenablog.com/entry/2025/03/19/073000より取得しました。


Goメモ-555 (weak)(弱参照, Go 1.24で追加)

関連記事

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

概要

以下、自分用のメモです。

Go 1.24 で weak が追加されました。C#やJavaにも存在する弱参照をサポートするライブラリですね。

www.bytesizego.com

基本的にライブラリなどのレイヤーで利用することが多く、あまり普段の実装では利用しないですね個人的には。

一応、自分用にサンプルをメモメモ。。。

サンプル

main.go

package main

import (
    "flag"
    "fmt"
    "runtime"
    "weak"
)

type (
    Args struct {
        UseWeakRef bool
    }

    MemStats struct {
        // ヒープに割り当てられたメモリの合計 (bytes)
        HeapAlloc uint64
    }
)

const (
    _          = iota
    KB float64 = 1 << (10 * iota)
    MB
    GB
)

var (
    args Args
)

func init() {
    flag.BoolVar(&args.UseWeakRef, "weakref", false, "use weak")
}

func main() {
    flag.Parse()

    if err := run(); err != nil {
        panic(err)
    }
}

func run() error {
    const (
        oneMib  = 1 << 20     // 1Mib
        bufSize = oneMib << 5 // 32Mib
    )

    switch args.UseWeakRef {
    case true:
        printMem("init  ", getMemStats())

        var (
            x                            = make([]byte, bufSize)
            weakRef weak.Pointer[[]byte] = weak.Make(&x) // https://pkg.go.dev/weak@go1.24.1
        )
        printMem("before", getMemStats())
        runtime.GC()
        printMem("after ", getMemStats())

        fmt.Printf("object is nil? ==> %v\n", weakRef.Value() == nil)

        //
        // runtime.KeepAlive() は、この呼び出しの時点まで引数に指定した
        // オブジェクトが生存していることをコンパイラとGCに対して保証させるもの。
        //
        runtime.KeepAlive(&weakRef)
    default:
        printMem("init  ", getMemStats())

        var (
            x         = make([]byte, bufSize)
            strongRef = struct{ b *[]byte }{&x}
        )
        printMem("before", getMemStats())
        runtime.GC()
        printMem("after ", getMemStats())

        fmt.Printf("object is nil? ==> %v\n", strongRef.b == nil)

        runtime.KeepAlive(&strongRef)
    }

    return nil
}

// メモリサイズをより読みやすい形式に変換
func formatBytes(bytes uint64) string {
    switch {
    case bytes >= uint64(GB):
        return fmt.Sprintf("%7.2f GB", float64(bytes)/GB)
    case bytes >= uint64(MB):
        return fmt.Sprintf("%7.2f MB", float64(bytes)/MB)
    case bytes >= uint64(KB):
        return fmt.Sprintf("%7.2f KB", float64(bytes)/KB)
    default:
        return fmt.Sprintf("%d bytes", bytes)
    }
}

func printMem(prefix string, stats MemStats) {
    fmt.Printf("[%s] HeapAlloc:   %s (ヒープメモリ)\n", prefix, formatBytes(stats.HeapAlloc))
}

func getMemStats() MemStats {
    var rtm runtime.MemStats

    runtime.ReadMemStats(&rtm)

    return MemStats{
        HeapAlloc: rtm.HeapAlloc,
    }
}

Taskfile.yml

# https://taskfile.dev

version: '3'

tasks:
  default:
    cmds:
      - go run main.go
      - sleep 1
      - go run main.go -weakref

shell

実行すると以下のように出力されます。

$ task
task: [default] go run main.go
[init  ] HeapAlloc:    185.22 KB (ヒープメモリ)
[before] HeapAlloc:     32.19 MB (ヒープメモリ)
[after ] HeapAlloc:     32.19 MB (ヒープメモリ)
object is nil? ==> false
task: [default] sleep 1
task: [default] go run main.go -weakref
[init  ] HeapAlloc:    185.50 KB (ヒープメモリ)
[before] HeapAlloc:     32.19 MB (ヒープメモリ)
[after ] HeapAlloc:    194.81 KB (ヒープメモリ)
object is nil? ==> true

weakパッケージを利用している方は開放されていますね。わずかに増えている分は weak.Pointer[[]byte] の分。

参考情報

Go 1.24 Release Notes - The Go Programming Language

Goのおすすめ書籍


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

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




以上の内容はhttps://devlights.hatenablog.com/entry/2025/03/19/073000より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14