0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】わざとメモリリークするサンプルコードと検出方法

Last updated at Posted at 2025-05-03

概要

  • Go言語を使っていてメモリリークを経験したことがないので、意図的にメモリリークを発生させるサンプルコードを書いてみた
  • メモリリークしているかも下記を使用して確認してみた
    • pprof(Goの標準profiler)
    • go tool pprof コマンドでメモリの使用状況を可視化

サンプルコード

package main

import (
	"fmt"
	"net/http"
	_ "net/http/pprof"
	"time"
)

// グローバル変数として巨大なスライスへの参照を保持
var leakedData = make([][]byte, 0)

func memoryLeak() {
	for {
		// 1MBのデータを作成
		data := make([]byte, 1024*1024)

		// グローバル変数にデータの参照を保持し続ける
		leakedData = append(leakedData, data)

		// 少し待つ
		time.Sleep(100 * time.Millisecond)
	}
}

func main() {
	// pprof用にHTTPサーバを起動(:6060でアクセス可能)
	go func() {
		fmt.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	// メモリリークを発生させる関数を呼び出し
	memoryLeak()
}

サンプルコード解説

  • net/http/pprof をimportすることで、http://localhost:6060/debug/pprof/ にアクセスできるようになる
  • memoryLeak() 関数内で1MBのデータを生成し続け、参照を leakedData に保持する
  • 本来なら使い終わったら開放されるべきだが、グローバル変数に参照が残ることでGCの対象にならずメモリを消費し続ける

pprofで確認

  1. ターミナルでサンプルコード実行

    1. go run main.go
  2. 別ターミナルで下記コマンドの実行

    1. go tool pprof http://localhost:6060/debug/pprof/heap
  3. topコマンド実行でメモリ食ってる関数を一覧表示

    1. ここで8.1MB全部が memoryLeak 関数内で確保され、解放されずに生き残ってるのがわかる
    (pprof) top
    Showing nodes accounting for 8.10MB, 100% of 8.10MB total
          flat  flat%   sum%        cum   cum%
        8.10MB   100%   100%     8.10MB   100%  main.memoryLeak (inline)
             0     0%   100%     8.10MB   100%  main.main
             0     0%   100%     8.10MB   100%  runtime.main
    
  4. list 関数名 コマンドで行単位の詳細確認

    (pprof) list main.memoryLeak
    Total: 8.10MB
    ROUTINE ======================== main.memoryLeak in /Users/isurugikeito/dev/go/go-demo/demo/low_layer/main.go
        8.10MB     8.10MB (flat, cum)   100% of Total
             .          .     13:func memoryLeak() {
             .          .     14:	for {
             .          .     15:		// 1MBのデータを作成
        8.10MB     8.10MB     16:		data := make([]byte, 1024*1024)
             .          .     17:
             .          .     18:		// グローバル変数にデータの参照を保持し続ける
             .          .     19:		leakedData = append(leakedData, data)
             .          .     20:
             .          .     21:		// 少し待つ
    
  5. web コマンドでブラウザ上でグラフで視覚化

    1. 使用するにはGraphvizが必要(Macならbrew install graphvizでインストール)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?