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?

【Java】GC(ガベージコレクション)、何となく任せてない? ― 仕組みをザックリ理解する

0
Last updated at Posted at 2026-03-18

はじめに

前回の記事で、new したオブジェクトはヒープに置かれることを学びました。では、使い終わったオブジェクトは誰が片付けてくれるのでしょうか?

その答えが GC(ガベージコレクション) です。C言語のように free() を書かなくていいのはGCのおかげですが、「何となく動いてくれてるんでしょ」で止まっているともったいない。この記事では、GCが何をしているのかをザックリ掴みます。

対象読者: Java実務1〜3年目。GCという言葉は知っているが、中身はよくわからないエンジニア


1. GCがやっていること ― ひとことで言うと

誰からも参照されなくなったオブジェクトを見つけて、ヒープから消す

これだけです。逆に言えば、どこかから参照されている限りオブジェクトは消えません

コードで確認

public class GcDemo {
    public static void main(String[] args) {
        String a = new String("Hello"); // ① オブジェクト生成、aが参照
        String b = new String("World"); // ② オブジェクト生成、bが参照

        a = null;  // ③ "Hello"への参照がなくなる → GC対象になる
        // この時点で "World" はまだbが参照しているので回収されない
    }
}

2. 世代別GCの考え方

JVMのGCは「ほとんどのオブジェクトはすぐ不要になる」という経験則に基づいて設計されています。これを**世代別GC(Generational GC)**と呼びます。

ヒープの構成

領域 役割 GCの特徴
Eden new したオブジェクトが最初に入る場所 いっぱいになるとMinor GCが走る
Survivor (S0/S1) Minor GCを生き延びたオブジェクトの一時置き場 S0とS1を交互に使う
Old世代 何度もMinor GCを生き延びた長寿オブジェクト Full GCで回収(重い処理)

ライフサイクルの流れ

// メソッドが呼ばれるたびに一時オブジェクトが大量に作られるケース
public List<String> processData(List<Integer> numbers) {
    return numbers.stream()
        .map(n -> "Item-" + n)    // ← ここで短命なStringが大量にnewされる
        .collect(Collectors.toList());
}
  1. "Item-" + n で作られるStringは Eden に入る
  2. Edenがいっぱいになると Minor GC が走る
  3. もう参照されていないStringはここで回収される(大半がこれ)
  4. まだ使われているオブジェクトは Survivor へ移動
  5. Survivorで何度も生き残ったオブジェクトは Old世代 へ昇格

つまり、短命なオブジェクトはYoung世代で素早く回収され、長生きするオブジェクトだけがOld世代に行くという効率的な仕組みです。


3. GCが走ると何が起きる? ― Stop-the-World

GCが動いている間、アプリケーションのスレッドは一時停止します。これを Stop-the-World(STW) と呼びます。

Minor GCの停止時間は通常ミリ秒単位なので、ほとんどのアプリケーションでは気になりません。ただし、Full GC(Old世代の回収) は数百ミリ秒〜数秒かかることがあり、レスポンスタイムに影響します。

実務での影響例

// ありがちなパターン:キャッシュをMapで持ち続ける
private static Map<String, Object> cache = new HashMap<>();

public void addToCache(String key, Object value) {
    cache.put(key, value);  // staticフィールドなのでGCに回収されない
    // → cacheが肥大化 → Old世代が圧迫 → Full GCが頻発
}

このようなコードは、意図せずOld世代を圧迫してFull GCの頻度を上げてしまいます。


4. GCの種類(ざっくり)

Java 11以降で使えるGCの代表的なものを紹介します。深入りはしませんが、名前だけ知っておくと調査時に役立ちます。

GCの種類 特徴 向いている用途
G1GC Java 9以降のデフォルト。バランス型 一般的なWebアプリ
ZGC STW時間を極端に短く抑える(1ms以下目標) 低レイテンシが求められるシステム
Shenandoah ZGCと同様の低停止時間を目指す 同上(OpenJDK系)

現時点では「G1GCがデフォルトで動いている」ということだけ押さえておけばOKです。


5. GCログを見てみよう(おまけ)

GCが実際にどう動いているかは、JVM起動オプションでログを出せます。

# Java 11以降
java -Xlog:gc* -jar myapp.jar

出力例(抜粋):

[0.015s][info][gc] Using G1
[1.234s][info][gc] GC(0) Pause Young (Normal) 24M->8M(256M) 3.456ms
[3.456s][info][gc] GC(1) Pause Young (Normal) 32M->10M(256M) 4.123ms

読み方:

  • Pause Young → Minor GC(Young世代の回収)
  • 24M->8M → GC前24MB使用 → GC後8MBに減った
  • 3.456ms → 停止時間

「Full GCが頻繁に出ていたら要注意」と覚えておけば、実務のトラブル調査で最初の手がかりになります。


まとめ

  • GCは参照されなくなったオブジェクトをヒープから消す仕組み
  • ヒープは Young世代(Eden + Survivor)Old世代 に分かれている
  • ほとんどのオブジェクトはYoung世代で短命に回収される
  • GC中はアプリが一時停止する(Stop-the-World
  • Full GCが頻発するとパフォーマンスに影響するので注意

次回は、GCでも回収しきれずヒープが溢れてしまった場合に起きる OutOfMemoryError の対処法を解説します。


シリーズ記事

  • 第1回: ヒープとスタック
  • 第2回: GC(ガベージコレクション)の基本(この記事)
  • 第3回: OutOfMemoryErrorが出たらどうする?(近日公開)
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?