Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Java, Go, Rustのメモリ管理手法の比較

Java, Go, Rustのメモリ管理手法の比較

「Java, Go, Rustのメモリ管理手法の比較」
Wada Takamichi

※この資料はJJUG CCC 2025 Springで発表した内容です。
https://jjug.doorkeeper.jp/events/183483
#jjug_ccc

More Decks by LINEヤフーTech (LY Corporation Tech)

Transcript

  1. 1 © LY Corporation 和⽥ 隆道 Wada Takamichi LINEヤフー株式会社 コマースカンパニー

    SC統括本部 開発本部 #LINEギフトのサーバーサイドエンジニア #新卒3年⽬ 前回のJJUGでも発表しました︕ 新卒2年⽬エンジニアがLINEギフトの保守 性を⾼めるために取り組んだこと
  2. Todayʼs Agenda 2 © LY Corporation 1. メモリの役割 2. Java,

    Go, Rustのメモリ管理⼿法 3. 負荷テストでパフォーマンス⽐較
  3. 発表の動機 © LY Corporation 3 l 普段の業務ではJavaを、ISUCONではGoを使っていたが、メモリがどのように管理されてい るか意識することは少なかった。GCを使っていることは知ってる l また、最近流⾏りのRustはGCがないらしい。どういうこと︖

    l それぞれどのようにメモリ管理してるのか、それはどのようにパフォーマンスに影響するの か、知りたい︕ ⾔語ごとにメモリ管理⼿法がどのように異なるのか知りたい
  4. 伝えたいこと © LY Corporation 4 ⾔語ごとにメモリ管理⼿法が様々で⾯⽩い︕アツい︕ l Java: 世代別GC l

    Go: エスケープ解析とシンプルなGC l Rust: Ownershipで管理してGC不要
  5. Todayʼs Agenda 5 © LY Corporation 1. メモリの役割 2. Java,

    Go, Rustのメモリ管理⼿法 3. 負荷テストでパフォーマンス⽐較
  6. メモリの構造 © LY Corporation 7 テキスト領域 静的領域 ヒープ領域 スタック領域 ︓プログラムを格納する領域

    ︓グローバル変数や静的変数を格納する領域 ︓動的に割り当てられる領域 ︓関数の引数・ローカル変数・戻り値を格納する領域
  7. メモリの構造 © LY Corporation 8 テキスト領域 静的領域 ヒープ領域 スタック領域 ︓プログラムを格納する領域

    ︓グローバル変数や静的変数を格納する領域 ︓動的に割り当てられる領域 ︓関数の引数・ローカル変数・戻り値を格納する領域 ヒープとスタックの管理⼿法は⾔語によって様々であり パフォーマンスへの影響が⼤きい
  8. Todayʼs Agenda 9 © LY Corporation 1. メモリの役割 2. Java,

    Go, Rustのメモリ管理⼿法 3. 負荷テストでパフォーマンス⽐較
  9. Todayʼs Agenda 10 © LY Corporation 1. メモリの役割 2. Java,

    Go, Rustのメモリ管理⼿法 3. 負荷テストでパフォーマンス⽐較
  10. スタック ヒープ Java: スタックとヒープの管理⼿法 © LY Corporation 16 Alice name

    age Alice 26 オブジェクトは基本的にヒープに割り当てられる printAlice main args
  11. スタック ヒープ Java: スタックとヒープの管理⼿法 © LY Corporation 17 Alice name

    age Alice 26 オブジェクトは基本的にヒープに割り当てられる printAlice alice main args
  12. スタック ヒープ Java: スタックとヒープの管理⼿法 © LY Corporation 24 Bob name

    age Bob 22 オブジェクトは基本的にヒープに割り当てられる Alice name age Alice 26 returnBob main args
  13. スタック ヒープ Java: スタックとヒープの管理⼿法 © LY Corporation 25 Bob name

    age Bob 22 オブジェクトは基本的にヒープに割り当てられる Alice name age Alice 26 returnBob bob main args
  14. ヒープ Java: Garbage Collection(GC) © LY Corporation 37 スタック object

    object object object object var ⽬的はヒープの不要なオブジェクトを解放すること
  15. ヒープ Java: Garbage Collection(GC) © LY Corporation 38 スタック object

    object object object object スタックの変数からオブジェクトの参照を辿る var
  16. ヒープ Java: Garbage Collection(GC) © LY Corporation 39 スタック object

    object object object object スタックの変数からオブジェクトの参照を辿る var
  17. ヒープ Java: Garbage Collection(GC) © LY Corporation 40 スタック object

    object object object object スタックの変数からオブジェクトの参照を辿る var
  18. ヒープ Java: Garbage Collection(GC) © LY Corporation 41 スタック object

    object object object object スタックの変数からオブジェクトの参照を辿る var
  19. ヒープ Java: Garbage Collection(GC) © LY Corporation 42 スタック object

    object object object object 参照のないオブジェクトがある var
  20. ヒープ Java: Garbage Collection(GC) © LY Corporation 43 スタック object

    object object object object 参照のないオブジェクトがある→解放する var
  21. ヒープ Java: Garbage Collection(GC) © LY Corporation 44 スタック object

    object object object object var 参照のないオブジェクトがある→解放する
  22. ヒープ Java: Garbage Collection(GC) © LY Corporation 45 スタック object

    object object var 参照のないオブジェクトがある→解放する
  23. ヒープ Java: Garbage Collection(GC) © LY Corporation 46 スタック object

    object object var また、Javaでは世代別という⼯夫を⽤いてGCを効率化している
  24. Java:世代別GCによる効率化 © LY Corporation 48 Eden Old Survivor Survivor object

    object オブジェクトはリージョンに割り当てられる ✱ Java9以降でデフォルトのG1GCについて説明
  25. Java:世代別GCによる効率化 © LY Corporation 49 Eden Eden Old Survivor Survivor

    リージョンは⽣存期間に基づいて世代に分類される ✱ Java9以降でデフォルトのG1GCについて説明 Eden Survivor Old
  26. Java:世代別GCによる効率化 © LY Corporation 50 Eden Eden Old Survivor Survivor

    若いリージョンを優先的にGCする(世代別GC) ✱ Java9以降でデフォルトのG1GCについて説明 Eden Survivor Old
  27. Java:世代別GCによる効率化 © LY Corporation 51 Old Eden Eden Survivor Survivor

    若いリージョンを優先的にGCする(世代別GC) Eden Survivor Old
  28. Survivor Java:世代別GCによる効率化 © LY Corporation 52 Old Eden Eden Survivor

    Survivor 不要オブジェクトを解放し、⽣存するオブジェクトはリージョンに集約する Eden Survivor Old
  29. Javaのメモリ管理⼿法: まとめ © LY Corporation 55 l オブジェクトは基本的にヒープに割り当てられる l 不要になったオブジェクトを解放するためにGCを⾏う

    l 若いオブジェクトを優先的にGCすることで効率化(世代別GC) 世代別GCで効率的に不要オブジェクトを解放
  30. スタック ヒープ Java:オブジェクトの割り当て⼿法 © LY Corporation 56 Bob name age

    Bob 22 Alice name age Alice 26 Bob alice オブジェクトは基本的にヒープに割り当てられる
  31. Go:オブジェクトの割り当て⼿法 © LY Corporation 57 スタック ヒープ Alice name old

    Alice 26 alice bob エスケープ解析でスタックとヒープのどちらに割り当てるか決める Bob name old Bob 22 ✱ JavaでもJITコンパイラで実⾏時にエスケープ解析するがGoほど積極的には働いていない
  32. スタック ヒープ Go: スタックとヒープの管理⼿法 © LY Corporation 65 printAlice alice

    スコープからエスケープしないオブジェクトはスタックに割り当てる main Alice name age Alice 26
  33. スタック ヒープ main Go: スタックとヒープの管理⼿法 © LY Corporation 72 returnBob

    スコープからエスケープするオブジェクトはヒープに割り当てる ✱ 実際にはインライン化によりエスケープしない扱いになってスタックに置かれることもある
  34. スタック ヒープ main returnBob Go: スタックとヒープの管理⼿法 © LY Corporation 73

    Bob name age Bob 22 スコープからエスケープするオブジェクトはヒープに割り当てる
  35. スタック ヒープ main returnBob Go: スタックとヒープの管理⼿法 © LY Corporation 74

    bob スコープからエスケープするオブジェクトはヒープに割り当てる Bob name age Bob 22
  36. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 88 main Alice

    name age Alice 26 printAlice ヒープにオブジェクトを割り当てる ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化
  37. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 89 printAlice alice

    ヒープにオブジェクトを割り当てる ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Alice name age Alice 26
  38. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 90 printAlice alice

    オブジェクトのOwnershipを変数aliceが持つ ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Alice name age Alice 26
  39. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 91 printAlice alice

    オブジェクトのOwnershipを変数aliceが持つ ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Alice name age Alice 26
  40. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 92 printAlice alice

    オブジェクトのOwnershipを変数aliceが持つ ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Alice name age Alice 26
  41. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 93 printAlice alice

    変数aliceが解放される ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Alice name age Alice 26
  42. Rust: スタックとヒープの管理⼿法 © LY Corporation 94 変数aliceが解放される スタック ヒープ ✱

    サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 printAlice alice main Alice name age Alice 26
  43. Rust: スタックとヒープの管理⼿法 © LY Corporation 95 変数aliceが解放される→Ownershipを持つオブジェクトも解放される スタック ヒープ ✱

    サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 Alice name age Alice 26 printAlice alice main
  44. Rust: スタックとヒープの管理⼿法 © LY Corporation 96 変数aliceが解放される→Ownershipを持つオブジェクトも解放される スタック ヒープ ✱

    サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main
  45. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 98 returnBob ✱

    サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main
  46. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 99 Bob name

    age Bob 22 returnBob ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 ヒープにオブジェクトを割り当てる main
  47. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 100 returnBob bob

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 main Bob name age Bob 22 ヒープにオブジェクトを割り当てる
  48. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 101 returnBob bob

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 オブジェクトのOwnershipを変数bobが持つ main Bob name age Bob 22
  49. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 104 main p

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 オブジェクトのOwnershipが移動する Bob name age Bob 22
  50. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 105 main p

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 オブジェクトのOwnershipが移動する Bob name age Bob 22
  51. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 106 main p

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 オブジェクトのOwnershipが移動する Bob name age Bob 22
  52. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 107 main p

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 変数pが解放される Bob name age Bob 22
  53. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 108 main p

    ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 変数pが解放される Bob name age Bob 22
  54. スタック ヒープ Rust: スタックとヒープの管理⼿法 © LY Corporation 109 main Bob

    name age Bob 22 p ✱ サイズ固定のオブジェクトはスタックに割り当てられるがOwnershipの説明のために単純化 変数pが解放される→Ownershipを持つオブジェクトも解放される
  55. Java, Go, Rustのメモリ管理⼿法: まとめ © LY Corporation 114 それぞれ異なる⼿法でメモリを管理している l

    Java: 世代別GC l Go: エスケープ解析とシンプルなGC l Rust: Ownershipで管理してGC不要
  56. Todayʼs Agenda 11 © LY Corporation 1. メモリの役割 2. Java,

    Go, Rustのメモリ管理⼿法 3. 負荷テストでパフォーマンス⽐較
  57. まとめ © LY Corporation 123 l Javaは世代別GC、Goはエスケープ解析とシンプルなGC、RustはOwnershipでGC不要 l 負荷テストでは、JavaはGCでスパイクが⽴つ、Goはヒープを使わないのでほぼ⼀定、 Rustは安定しているがヒープを使うので少しばらつく、と⾔う結果だった

    l ⼀⽅で、それぞれ最適化の余地は⼗分にあるし、設定によって結果も変動する l Java: JVMパラメータ調整、他のGCアルゴリズム、JITコンパイラが効くように実装 l Go: (ヒープ使ってるなら)スタック使うように実装、GCパラメータ調整、アリーナ l Rust: スタック使うように実装、メモリアロケータの選択 それぞれ異なる⼿法でメモリを管理している それによってパフォーマンスの特性が異なることも確認できた
  58. 参考⽂献 © LY Corporation 124 1. ORACLE ガベージ・コレクション・チューニング・ガイド 2. Garbage

    First Garbage Collection (G1 GC) #jjug_ccc #ccc_cd6 3. Visualizing memory management in JVM(Java, Kotlin, Scala, Groovy, Clojure) 4. Go⾔語のGCについて - LINE Engineering 5. Getting to Go: The Journey of Goʻs Garbage Collector – The Go Blog 6. The Rust Programming Language