ホーム › ガベージコレクション(GC) › GC-03
GC-03: FullGC を避けるメモリ効率設計
FullGC が発生するとアプリが一時停止(Stop-The-World)します。この停止を最小限に抑えるための コード設計パターンを学びましょう。WeakReference・SoftReference・ 短命オブジェクト設計など、実践的な手法を解説します。
いつ使うか
- バッチ処理で大量データを扱い、途中でメモリが枯渇しそうなとき
- メモリを使うキャッシュを作りたいが、OOM は避けたいとき
- 長時間稼働するサーバーアプリでメモリリークを防ぎたいとき
- GC の停止時間を計測したら想定以上に長かったとき
参照の種類と GC の挙動
| 参照の種類 | クラス | GC での挙動 |
|---|---|---|
| 強参照(Strong) | 通常の変数代入 | 参照がある限り回収されない |
| 弱参照(Weak) | WeakReference | 次の GC で回収される |
| 軟参照(Soft) | SoftReference | メモリ不足時のみ回収(キャッシュ向き) |
| ファントム参照 | PhantomReference | GC 後の後処理用(上級者向け) |
サンプルコード
WeakHashMap のキーは WeakReference で保持されています。強参照がなくなると GC に回収され、マップからも自動的に除去されます。キャッシュとして活用すると、メモリ不足時に自動解放される安全なキャッシュになります。
よくあるミス・注意点
WeakReference は null になる可能性を常に考慮する
weakRef.get() は GC が発生した後に null を返すことがあります。 取得後は必ず null チェックをしてから使いましょう。 null のまま使うと NullPointerException が発生します。
static コレクションへの追加は Old Generation を圧迫する
static フィールドのリストやマップに追加し続けると、 オブジェクトが永続的に参照され続けて Old Generation に移動します。 Old Generation がいっぱいになると FullGC が発生します。 定期的なクリアや最大サイズの制御を忘れないようにしましょう。
内部クラスは外側のクラスへの参照を持つ
非静的な内部クラス(匿名クラスを含む)は、自動的に外側のクラスのインスタンスへの参照を保持します。 内部クラスのオブジェクトが長命である場合、外側のオブジェクトも GC されなくなります。 long-lived な内部クラスには static 内部クラスを使いましょう。
テストする観点
WeakHashMapに格納したデータは、 強参照を null にして System.gc() を呼ぶとサイズが減ること- メソッドスコープ内で作成した大量のオブジェクトは、メソッド終了後に GC で回収されること
WeakReference.get()は GC 後に null を返すことがあるため、null チェックが必要なこと(境界値テスト)- static フィールドに保持したオブジェクトは GC されないこと(メモリリーク確認)