ホーム › ガベージコレクション(GC) › GC-01
GC-01: Mark & Sweep・Generational GC の基本
Java の GC(ガベージコレクション)がどのようにメモリを自動管理するかを理解しましょう。 Mark & Sweep の仕組み、Young/Old Generation の役割、そして GC の動作をRuntime クラスで観察する方法を学びます。
いつ使うか
- アプリが遅い原因として GC の頻発を疑ったとき
OutOfMemoryErrorが発生してメモリリークを調査したいとき- バッチ処理や大量データ処理でメモリ使用量の変化を監視したいとき
- GC ログを読んで Young/Old Generation の状況を把握したいとき
GC の基本概念
| 領域 | 役割 | GC の種類 |
|---|---|---|
| Young Generation | 新しく作成されたオブジェクト置き場 | Minor GC(短時間・頻繁) |
| Old Generation | 長生きしたオブジェクトの置き場 | Full GC(長時間・アプリ一時停止) |
| Metaspace | クラス定義の情報(Java 8+) | 特定条件下で回収 |
Mark & Sweep: まず「到達可能なオブジェクト(Mark)」を辿り、到達できないものをゴミとして「削除(Sweep)」するアルゴリズムです。
サンプルコード
Java 8 では Runtime.getRuntime() でメモリ情報を取得します。System.gc() は GC の実行をリクエストしますが、必ず即座に実行されるとは限りません。finalize() はデストラクタとして使ってはいけません(実行タイミングが JVM に依存するため)。
よくあるミス・注意点
System.gc() は本番コードで使わない
System.gc() は GC の実行を JVM にリクエストしますが、 必ず実行される保証はありません。また本番環境では不意な GC 停止を引き起こす可能性があります。 動作確認用途にとどめ、本番コードには含めないようにしましょう。
finalize() をデストラクタとして使ってはいけない
finalize() メソッドは GC 時に呼ばれる可能性がありますが、 呼ばれるタイミングは不定で、呼ばれないこともあります。 リソースの確実な解放には try-with-resources を使いましょう。 Java 9 以降は非推奨、Java 18 以降は削除予定です。
長命なオブジェクトが Old Generation を圧迫する
static フィールドや長期間参照が続くコレクションにオブジェクトを追加し続けると、 Old Generation が増え続けます。定期的なクリアや WeakReference の活用で Old Generation を小さく保ちましょう。
テストする観点
Runtime.getRuntime().maxMemory()が JVM 起動オプション-Xmxで設定した値と一致すること- 大量のオブジェクト生成後に System.gc() を呼び出すと、使用メモリが減少すること
- ローカル変数として作成したオブジェクトはメソッド終了後に GC 対象になること(参照が外れること)
- static フィールドに保持したオブジェクトは GC で回収されないこと(メモリリークの再現)