---
title: "ガベージコレクション（garbage collection）とは？仕組み・アルゴリズム・言語別の違いとGCログの見方"
url: "https://www.issoh.co.jp/tech/details/3366/"
published: 2024-08-21
updated: 2026-10-11
categories: ["Java"]
publisher: "株式会社一創"
---

# ガベージコレクション（garbage collection）とは？仕組み・アルゴリズム・言語別の違いとGCログの見方

ガベージコレクション（Garbage Collection、GC）は、プログラムが使わなくなったメモリ領域を実行環境が自動で見つけて解放する仕組みです。C言語の `malloc`／`free` のように開発者が手作業でメモリを返す必要がなくなり、解放漏れ（メモリリーク）や二重解放といったバグを構造的に減らせます。この記事では、GCが「どのメモリをごみと判断するのか」という基本原理から、マーク・アンド・スイープや世代別GCといった代表的なアルゴリズム、Java・C#・Python・Goなど言語ごとの2026年時点の実装差、Pythonで実際に回収の様子を確かめるコード、GCログで停止時間を測る手順、そして `System.gc()` を手動で呼ぶべきかという実務の論点までを、公式ドキュメントへのリンクつきで整理します。

## まとめ：ガベージコレクションの仕組みと言語別の違いを先に整理

- **GCとは**：どこからも参照されなくなった（＝到達不能になった）オブジェクトを実行環境が自動回収し、メモリを再利用可能にする仕組み。手動メモリ管理のリークと二重解放を防ぐのが目的。
- **基本原理**：GCは「もう使わない」を**ルート（スタック変数・グローバル変数など）からたどれるか＝到達可能性**で判定する。到達できないオブジェクトがごみ。
- **代表アルゴリズム**：マーク・アンド・スイープ／参照カウント／コピー／コンパクション／世代別GC。多くの実行環境はこれらを組み合わせる。
- **言語ごとに違う**：Javaは世代別のトレーシングGC（既定はG1）、Pythonは参照カウント＋循環参照用の世代別GC、C#/.NETも世代別GC、GoはコンカレントなマークGC（1.26系でGreen Tea GCが既定）。C/C++とRustには言語標準のGCがない。
- **測ってから調整する**：停止時間や回収頻度はGCログ（Javaの `-Xlog:gc`、Goの `GODEBUG=gctrace=1`）で数値として確認し、ヒープ上限やGC種別の変更はその結果を根拠に行う。
- **手動呼び出しは原則不要**：`System.gc()`（Java）や `GC.Collect()`（C#）は基本的に呼ばない。Pythonの `gc.collect()` は循環参照を即時回収したい特殊ケースに限る。

## ガベージコレクションとは：自動メモリ管理の定義と手動管理との違い

ガベージコレクションとは、ヒープ上に確保されたオブジェクトのうち**プログラムから二度と使われないもの**を実行環境（ランタイム）が自動的に検出し、そのメモリを解放して再利用できるようにする自動メモリ管理の仕組みです。「ガベージ（garbage）＝ごみ」を「コレクション（collection）＝回収」することからこの名前が付いています。回収を担う部品はガベージコレクタと呼ばれ、どちらもGCと略されます。表記のゆれとして「ガーベジコレクション」「ガベコレ」などとも呼ばれますが、指している概念は同じです。

### 手動メモリ管理との違い：GCによるリークと二重解放の回避の仕組み

GCが普及する前、C言語などでは開発者が `malloc` で確保したメモリを `free` で明示的に返す必要がありました。この方式で典型的に起きるバグは、次の二つです。ひとつは**メモリリーク**で、解放を忘れると使われないメモリが積み上がり、長時間動くサーバなどでは最終的にメモリ枯渇でクラッシュします。もうひとつは**二重解放（ダングリングポインタ）**で、すでに解放した領域を再度解放したり参照したりすると未定義動作になります。GCは「不要になったら実行環境が回収する」という方針でこの両方を根本から回避します（メモリリークの詳しい原因と対処は[メモリリークとは？原因の特定方法と直し方](https://www.issoh.co.jp/tech/details/3621/)を参照）。

ただし、GCがあればリークが起きないわけではありません。GCが回収するのは「到達できないオブジェクト」だけなので、静的なキャッシュやイベントリスナーの登録解除漏れのように**参照が残り続けるオブジェクトは、使っていなくても回収されません**。GC言語のメモリリークは、ほぼこの「参照の取り残し」が原因です。

### GCを持たない言語の管理方法：RAIIと所有権による解放の自動化

GCを持たない言語も、すべてを手作業で管理しているわけではありません。C++はRAII（オブジェクトの寿命とリソースの確保・解放をスコープに結び付ける設計）と `unique_ptr`・`shared_ptr` などのスマートポインタで解放を自動化します。Rustはさらに一歩進め、コンパイル時に「誰がその値を所有しているか」を検査する所有権の仕組みで、実行時のGCなしにメモリ安全性を保証する仕組みです。値がスタックとヒープのどちらに置かれるかという前提は[Rustのスタックとヒープ｜値がヒープへ脱出する条件とメモリ領域の使い分け](https://www.issoh.co.jp/tech/details/2814/)で解説しています。GCは「実行時に到達可能性を調べる」方式、所有権は「コンパイル時に寿命を決める」方式と覚えておくと、両者の位置づけを取り違えません。

### GCのメリットとトレードオフ：メモリ管理の安全性と停止時間の負担

GCの利点はメモリ管理の自動化による安全性と開発効率の向上ですが、無償ではありません。GCはCPU時間を消費し、回収処理のためにアプリケーションのスレッドを一時停止させる**Stop-the-World（STW）**が発生します。停止時間が長いと応答性が落ちるため、低遅延が求められるシステムでは停止を短くするGCの選定やチューニングが必要です。「自動だから何も考えなくてよい」わけではなく、**GCの挙動を理解したうえで大量のオブジェクト生成を避ける設計が、GCの負荷そのものを下げます**。たとえばC#では値型を `object` として扱うだけでヒープ割り当てが発生し、GCの仕事が増えます（具体例は[C#のボックス化とは？起きる場面と割り当てバイト数を.NET 10で実測](https://www.issoh.co.jp/tech/details/4277/)）。

## ルートからの到達可能性で「ごみ」を決めるGCの基本的な仕組み

GCの中心的な考え方は**到達可能性（reachability）**です。実行環境は、確実に生きている参照の起点である**ルート集合**（スタック上のローカル変数、CPUレジスタ、グローバル／静的変数など）を出発点に、参照をたどれるオブジェクトを「生存」と見なします。ルートからどの経路でもたどり着けないオブジェクトは、プログラムが二度と使えないため「ごみ」と確定し、回収対象になります。

この「参照をたどって生存を判定する」方式を総称して**トレーシングGC**と呼びます。後述するマーク・アンド・スイープやコピーGC、世代別GCはいずれもトレーシングGCの一種です。一方、参照カウントは各オブジェクトが参照された回数を数える別系統の方式で、両者を組み合わせる言語もあります。

到達可能性の判定は、メモリ回収以外にも応用されています。Go 1.26では実験機能として、ブロックされたゴルーチンが待っているチャネルやロックが到達不能なら「二度と起きない＝リークしている」と判定するプロファイルが追加されました（[Go 1.26 Release Notes](https://go.dev/doc/go1.26)）。ゴルーチン自体の仕組みは[ゴルーチン（Goroutine）とは？Go言語の並行処理を支える軽量スレッドの仕組み](https://www.issoh.co.jp/tech/details/4632/)を参照してください。

## マーク＆スイープから世代別まで、代表的なGCアルゴリズム5種の特徴

ガベージコレクションのアルゴリズムには代表的なものがいくつかあり、それぞれ長所と短所が異なります。実際の実行環境は単一の方式ではなく、これらを組み合わせて使うのが一般的です。

### マーク・アンド・スイープ：基本的なトレーシングGCの回収手順と断片化

最も古典的で広く使われる方式です。二段階で動作します。**マーク**フェーズでルートから到達可能なオブジェクトすべてに印を付け、**スイープ**フェーズで印の付いていないオブジェクトを解放します。実装が単純で確実ですが、解放後のメモリに空き領域が飛び飛びに残る**断片化（フラグメンテーション）**が起きやすく、大きな連続領域を確保しづらくなる点が欠点です。断片化は後述のコンパクションで解消します。

### 参照カウント：不要なオブジェクトの即時回収と循環参照での回収の限界

各オブジェクトに「今いくつの参照から指されているか」というカウンタを持たせ、参照が増えれば+1、外れれば-1し、**カウントが0になった瞬間に解放**する方式です。不要になった直後に回収できSTWが起きにくい反面、二つのオブジェクトが互いを参照し合う**循環参照**ではカウントが0にならず回収できません。このためPythonのように、参照カウントを主軸にしつつ循環参照専用のトレーシングGCを併用する言語があります。Swiftは参照カウント（ARC）だけで動くため、循環参照は `weak` 参照で開発者が断ち切る必要があります。

### コピーGC：生存オブジェクトの連続配置による断片化の回避と領域の二分

ヒープを二つの領域に分け、生存オブジェクトだけを一方からもう一方へ詰めてコピーし、元の領域は丸ごと解放する方式です。生存物を連続配置するため**断片化が起きず**、確保も速い一方、常に片側を空けておく必要があり**実質的に使えるメモリが半分**になります。生存率が低い（＝すぐ死ぬオブジェクトが多い）領域と相性がよく、後述の世代別GCの若い世代でよく使われます。V8（Chrome・Node.jsのJavaScriptエンジン）も若い世代にこの方式を採り、複数スレッドで並列にコピーしています（[V8公式ブログ「Trash talk: the Orinoco garbage collector」](https://v8.dev/blog/trash-talk)）。

### コンパクション：生存オブジェクトの詰め直しによる断片化の解消と移動コスト

コンパクション（compaction）は、生存オブジェクトをメモリの片側に隙間なく詰め直し、連続した空き領域を作る操作です。マーク・アンド・スイープの断片化を解消し、大きなオブジェクトを確保しやすくします。オブジェクトの移動コストがかかるため頻繁には行えませんが、長時間稼働するシステムの断片化対策として有効です。

### 世代別GC：大半のオブジェクトが短命という仮説と世代ごとの回収方式

「生成されたオブジェクトの大半は短命で、長く生き残るものは少ない」という**世代仮説**に基づく方式です。ヒープを**若い世代（Young / 新世代）**と**古い世代（Old / 老世代）**に分け、頻度と手法を変えて回収します。若い世代を対象とする軽い回収を**マイナーGC（Minor GC）**、古い世代も含む重い回収を**メジャーGC（Major GC）**と呼びます。JavaでいうFull GCは、ヒープ全体（新世代・老世代・場合によりメタ領域）を対象にする最も重い回収を指し、頻発すると停止時間が伸びるため避けたいイベントです。若い世代でGCを生き延びたオブジェクトは古い世代へ「昇格」します。.NETはGen0・Gen1・Gen2の3世代に加え、大きなオブジェクト専用のLOH（Large Object Heap）を持ちます（[Microsoft Learn「Fundamentals of garbage collection」](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals)）。

| アルゴリズム   | 断片化  | 循環参照 | 回収タイミング | 主な使いどころ       |
| -------- | ---- | ---- | ------- | ------------- |
| マーク&スイープ | 起きる  | 回収可  | まとめて    | 汎用・基礎         |
| 参照カウント   | 起きうる | 回収不可 | 即時      | Python・Swift等 |
| コピー      | 起きない | 回収可  | まとめて    | 若い世代          |
| コンパクション  | 解消する | 回収可  | まとめて    | 断片化対策         |
| 世代別      | 実装次第 | 回収可  | 世代ごと    | Java・.NET等    |

## Java・C#・Python・Go・JavaScriptのGC実装と2026年時点の版

GCは言語ごとに実装が大きく異なります。同じ「自動メモリ管理」でも、採用アルゴリズムや手動介入の可否が違う点は、複数言語を扱う開発者がつまずきやすいところです。下表は2026年10月時点の各公式ドキュメントで確認した内容です。

| 言語／環境           | 主なGC方式          | 手動トリガ                    | 特徴                |
| --------------- | --------------- | ------------------------ | ----------------- |
| Java（JVM）       | 世代別トレーシング（既定G1） | `System.gc()`※非推奨        | G1・ZGC等を選択可       |
| C#（.NET）        | 世代別（Gen0〜2）     | `GC.Collect()`※非推奨       | サーバGC／ワークステーションGC |
| Python（CPython） | 参照カウント＋循環用世代別   | `gc.collect()`           | 参照カウントは無効化不可      |
| Go              | コンカレントなマーク&スイープ | `runtime.GC()`           | 1.26系でGreen Tea既定 |
| JavaScript（V8）  | 世代別トレーシング       | Node.jsは`--expose-gc`時のみ | Chrome／Node.jsで採用 |
| C／C++・Rust      | 言語標準のGCなし       | —                        | RAII・所有権で管理       |

### Python：参照カウントと循環GC、3.14系での差し戻し

特徴的なのはPython（CPython）で、参照カウントを常時使いつつ、参照カウントでは回収できない循環参照だけを世代別のトレーシングGC（`gc` モジュール）が回収します。参照カウントは言語の根幹なので無効化できませんが、循環GCは `gc.disable()` で止められます（[Python公式ドキュメント「gc — Garbage Collector interface」](https://docs.python.org/3/library/gc.html)）。

版による違いにも注意が要ります。Python 3.14.0から3.14.4には停止時間を短くするインクリメンタルGCが搭載されましたが、本番環境でメモリ使用量が大きく増えるという報告が相次ぎ、**3.14.5で3.13と同じ世代別GCへ差し戻されました**（[What’s New In Python 3.14](https://docs.python.org/3/whatsnew/3.14.html)）。3.14系でGCの閾値やメモリ挙動を調べる場合は、パッチ版まで確認したうえで比較してください。

### Go：低遅延のコンカレントGCとGreen Tea GCの既定化

Go言語は、停止時間を極小化することを重視したコンカレントなマーク&スイープを採用し、GCとアプリケーションを並行実行します。Go 1.25で実験機能だったGreen Tea GCは、**Go 1.26で既定**になりました。小さなオブジェクトのマーク・走査の局所性を高めた設計で、リリースノートはGC負荷の10〜40%削減を見込むとしています。性能や挙動の理由で戻したい場合は、ビルド時に `GOEXPERIMENT=nogreenteagc` を指定します（この無効化手段は1.27で削除予定。[Go 1.26 Release Notes](https://go.dev/doc/go1.26)）。

### .NET：世代別GCの構成とDATASによるヒープサイズの動的調整

.NETは世代別GCを基本に、サーバ向けの「サーバGC」とデスクトップ向けの「ワークステーションGC」を切り替えられます。サーバGCでは、負荷に合わせてヒープの大きさを動的に調整するDATAS（Dynamic Adaptation To Application Sizes）が.NET 8でオプトイン導入され、.NET 9で既定有効になりました（[Microsoft Learn「Dynamic adaptation to application sizes (DATAS)」](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/datas)）。コンテナで多数のプロセスを詰めて動かす構成では、この既定変更でメモリ使用量の見え方が変わる点を押さえておきます。

### Java：既定のG1と低遅延用途のZGCの選択、世代別モードへの移行

JVMはヒープを新世代（Eden＋Survivor）と老世代に分け、複数のGC実装から選べます。既定は**G1 GC**（Java 9以降）で、低遅延用途では**ZGC**が使われます。ZGCはJDK 21で世代別モードが追加され（[JEP 439](https://openjdk.org/jeps/439)）、JDK 23で世代別が既定に（[JEP 474](https://openjdk.org/jeps/474)）、JDK 24で非世代別モードが削除されました（[JEP 490](https://openjdk.org/jeps/490)）。JDK 24以降は `-XX:+UseZGC` だけで世代別ZGCが動き、`-XX:+ZGenerational` を付ける必要はありません。JVM自体の役割は[Java仮想マシン（JVM）とは](https://www.issoh.co.jp/tech/details/7151/)を参照してください。

## PythonでGCを動かし、循環参照が回収される様子をコードで確かめる

参照カウントと循環GCの違いを理解するには、手元でコードを動かして挙動を比べる方法が有効です。次のスクリプトは、互いを参照し合う2つのオブジェクトを作り、循環GCを止めた状態で変数を消しても残ること、`gc.collect()` で回収されることを弱参照（`weakref`）で観測します。標準ライブラリだけで動くので、そのままファイルに保存して実行できます。

```
import gc
import sys
import weakref


class Node:
    def __init__(self, name):
        self.name = name
        self.peer = None


gc.disable()                      # 循環GCを止め、参照カウントだけの挙動を見る
a, b = Node("a"), Node("b")
a.peer, b.peer = b, a             # a と b が互いを指す循環参照
probe = weakref.ref(a)            # a が回収されたかを弱参照で観測する
del a, b                          # 変数名を消しても互いの参照が残る
print("del直後に残っているか:", probe() is not None)
print("gc.collect()の戻り値:", gc.collect())
print("collect後に残っているか:", probe() is not None)
gc.enable()
print("Python", sys.version.split()[0], "閾値:", gc.get_threshold())
```

Windows上のPython 3.14.6で実行すると、出力は次のようになりました。

```
del直後に残っているか: True
gc.collect()の戻り値: 38
collect後に残っているか: False
Python 3.14.6 閾値: (2000, 10, 10)
```

1行目の `True` は、変数 `a`・`b` を消しても互いの参照でカウントが1のまま残るため、参照カウントだけでは回収されないことを示しています。`gc.collect()` の戻り値は「見つかった到達不能オブジェクトの数」で、起動時に生じた他のごみも含むため環境や版によって変わります。数値そのものより、3行目が `False` に変わった点を確認してください。これは循環GCが到達不能な2つを回収したことを示すためです。`get_threshold()` の値も版によって異なるので、チューニング前に自分の環境で出力しておきます。

## GCログとgctraceで停止時間を測り、ヒープとGC種別を調整する手順

GCの調整は「測る」から始めます。停止時間が長い、Full GCが頻発している、といった兆候は勘ではなくログの数値で確認し、ヒープサイズやGC種別の変更はその結果を根拠に行います。

### Java：-Xlog:gcによるGCログの出力と停止時間の確認手順

```
# G1でGCログをファイルに出す例（ヒープは初期512MB・上限2GB）
java -Xms512m -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xlog:gc*:file=gc.log:time,uptime,level,tags -jar app.jar

# 低遅延用途でZGCに切り替える例（JDK 24以降は世代別ZGCが自動で使われる）
java -Xmx2g -XX:+UseZGC -Xlog:gc:file=gc.log -jar app.jar

# 稼働中のJVMのヒープ使用状況を1秒ごとに見る（<pid>は jcmd -l で確認）
jstat -gcutil <pid> 1000
```

`-Xms`／`-Xmx` はヒープの初期・最大サイズ、`-XX:MaxGCPauseMillis` はG1が目標とする最大停止時間です。GCログには、いつ・どのGCが・何ミリ秒停止して・どれだけ解放したかが記録されます。「Pause Full」が繰り返し出る、回収後も老世代の使用量が下がらない、といった兆候があれば、ヒープ不足かメモリリークの可能性を調べる必要があります。各オプションの意味とGC種別ごとの調整項目はOracleの[HotSpot Virtual Machine Garbage Collection Tuning Guide（Release 25）](https://docs.oracle.com/en/java/javase/25/gctuning/)で確認可能です。G1・ZGCの選び分けや世代構造の詳細は[Javaのガベージコレクション（GC）とは｜仕組み・種類・ログ確認とチューニング手順](https://www.issoh.co.jp/tech/details/3084/)、ヒープの内部構造やOutOfMemoryErrorの対処は[Javaヒープのメモリ構造とサイズ設定](https://www.issoh.co.jp/tech/details/3365/)で詳しく扱っています。

### Go：GODEBUG=gctraceとGOGC・GOMEMLIMITで回収頻度を決める

```
# GCが走るたびに1行のトレースを標準エラーへ出す
GODEBUG=gctrace=1 go run .

# 回収頻度を下げてCPU負荷を減らし、メモリ上限は1GiBで抑える例
GOGC=200 GOMEMLIMIT=1GiB ./app
```

Goの回収頻度は主に2つの値で決まります。`GOGC` は「前回のGC後に生きていたヒープに対して、どれだけ増えたら次のGCを走らせるか」の百分率で、既定は100です。値を上げるとGC回数とCPU負荷が減る代わりにメモリ使用量が増えます。`GOMEMLIMIT` はメモリ使用量の上限の目安で、コンテナのメモリ制限に近づいたときにGCを早めに走らせる用途向けです。両者の関係はGo公式の[A Guide to the Go Garbage Collector](https://go.dev/doc/gc-guide)が図つきで説明しています。

### 本番環境での継続的な計測：GCログとプロファイリングによる原因の切り分け

GCログは「GCがどれだけ止めたか」を教えてくれますが、「どのコードが大量にオブジェクトを作っているか」までは分かりません。割り当ての多い関数を特定するにはアロケーションプロファイルが必要で、本番環境で常時取得する方法は[Continuous Profilingとは｜継続的プロファイリングの仕組み・フレームグラフ・導入判断](https://www.issoh.co.jp/tech/details/15709/)で解説しています。GCの停止時間とアロケーションの多い箇所を突き合わせると、チューニングで済むのかコード修正が要るのかを切り分けられます。

## System.gc()・GC.Collect()・gc.collect()の手動実行判断

「メモリを早く解放したいのでGCを手動で呼びたい」という要望はよくありますが、**ほとんどの場合、手動呼び出しは避けるべき**です。理由を言語別に整理します。

```
// Java: 原則呼ばない。あくまで「実行を提案」するだけで強制ではない
System.gc();

// C#/.NET: 原則呼ばない。全世代の重い回収を誘発しやすい
GC.Collect();
```

```
# Python: 循環参照を今すぐ回収したい特殊ケースに限る
import gc
gc.collect()
```

`System.gc()` は「GCを実行してほしい」という**要求にすぎず、JVMが実際に実行する保証はありません**。Java APIドキュメントも「GCを走らせるよう提案する」と表現しています（[Java SE 25 API「Class System」](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/System.html)）。しかも呼ぶと最も重いFull GCを誘発しやすく、本来JVMが状況を見て決める回収のタイミングを乱して**かえって停止時間を増やす**ことが多いのが実情です。C#の `GC.Collect()` も同様に全世代回収を招きやすく、通常は不要です。手動呼び出しでメモリリークが直ることはありません。**回収されないのは「まだ参照が残っているから」であり、参照を切ること（不要な参照をnullにする、キャッシュを適切に破棄する）が本質的な対処**です。

例外はPythonの `gc.collect()` です。参照カウントで回収しきれない循環参照を、メモリ逼迫前に明示的に回収したい場面や、大量オブジェクト処理の区切りで循環GCを走らせたい場面では意味があります。それでも常用ではなく、プロファイリングで必要性を確認したうえでの限定利用にとどめるのが妥当です。

## GCの停止が問題になる条件と、GC言語を採用する・見送る場面の判断

ここまでの内容を、言語・実行環境を選ぶ立場での判断にまとめます。結論から言うと、**業務システムやWebアプリケーションの大半は、GC言語を選び、既定のGCのまま運用して問題ありません**。GCの停止時間が問題になるのは、限られた条件がそろったときです。

### GC言語をそのまま採用してよい条件：応答時間の要件と開発・保守の効率

- 応答時間の要件が数百ミリ秒単位で、数ミリ秒〜数十ミリ秒の停止が利用者に見えない（一般的な業務Web、管理画面、バッチ）
- 開発速度と保守のしやすさを優先し、メモリ管理のバグを構造的に減らしたい
- Java・C#・Go・Pythonの開発者を確保しやすく、既存資産もこれらの言語にある

### GCの調整や別の選択肢を検討する場面：停止時間・メモリ制限・ヒープ規模

- **停止の上限が厳しい**：金融の約定処理や広告入札など、p99で数ミリ秒を守る必要がある。まずJavaならZGC、GoならGOGC・GOMEMLIMITの調整で要件を満たせるかを測り、満たせない部分だけをGCを持たないRustやC++で書く
- **メモリが極端に限られる**：組み込み機器やエッジ端末で、GCのための余裕を持ったヒープを確保できない
- **ヒープが巨大で長時間動く**：数十GB級のヒープでFull GCが起きると停止が秒単位になりうる。G1のままでよいかをGCログで確かめ、必要ならZGCを試す

見送りの判断をする前に、GCログとプロファイルで「本当にGCが原因か」を確かめてください。応答が遅い原因がGCではなくSQLや外部API呼び出しだった、という例は珍しくありません。稼働中のシステムでメモリ使用量が増え続ける、夜間に応答が止まるといった症状の調査と性能改善を外部に任せたい場合は、一創の[保守運用・内製化支援](https://www.issoh.co.jp/service/system/maintenance/)でGCログの解析から設定変更・コード修正まで対応しています。

## よくある質問：Full GC・GCアルゴリズム・手動実行・GCログ・Python

### Full GC（フルGC）とは何ですか？

ヒープ全体（新世代・老世代、実装によってはメタ領域）を対象にする最も重いガベージコレクションです。停止時間が長くなりやすいため、Full GCが頻発している場合はヒープ不足やメモリリーク、GC設定の見直しが必要なサインと考えてください。

### GCアルゴリズムにはどんな種類がありますか？

基礎となるのはマーク・アンド・スイープ、参照カウント、コピー、コンパクション、世代別GCです。実際のJavaのG1やZGC、.NETのGC、GoのGreen Tea GCなどは、これらを組み合わせたり改良したりして実装されています。

### 手動でガベージコレクションを実行できますか？

Javaの `System.gc()`、C#の `GC.Collect()`、Pythonの `gc.collect()`、Goの `runtime.GC()` で要求できますが、Java・C#では原則非推奨です。特にJavaの `System.gc()` は実行の保証がなく、停止時間を悪化させることが多いため、通常は実行環境に任せます。

### GCログとは何ですか？どう有効化しますか？

GCの発生時刻・種別・停止時間・解放量を記録したログです。Javaでは起動オプション `-Xlog:gc`（JDK 9以降の統合ログ形式）で有効化し、Goでは環境変数 `GODEBUG=gctrace=1` でGCごとのトレースを出せます。Full GCの頻度や停止時間の分析、チューニングの根拠に使います。

### Pythonにもガベージコレクションはありますか？

あります。CPythonは参照カウントを主軸に、参照カウントでは回収できない循環参照を世代別のトレーシングGC（`gc` モジュール）で回収する二層構成です。参照カウントは無効化できませんが、循環GCは `gc.disable()` で停止できます。3.14系では3.14.5でGC方式が差し戻されているため、版を確認してから挙動を比べてください。

## 関連記事

- [Javaのガベージコレクション（GC）とは｜仕組み・種類・ログ確認とチューニング手順](https://www.issoh.co.jp/tech/details/3084/)
- [メモリリークとは？原因の特定方法と直し方を言語・環境別に解説](https://www.issoh.co.jp/tech/details/3621/)
- [Javaヒープとは？メモリ構造・サイズ設定・OutOfMemoryErrorの対処](https://www.issoh.co.jp/tech/details/3365/)
- [Java仮想マシン（JVM）とは？仕組み・メモリ構成・JITを実機の出力で解説](https://www.issoh.co.jp/tech/details/7151/)
- [Rustのスタックとヒープ｜値がヒープへ脱出する条件とメモリ領域の使い分け](https://www.issoh.co.jp/tech/details/2814/)
- [Continuous Profilingとは｜継続的プロファイリングの仕組み・フレームグラフ・導入判断を実装目線で解説](https://www.issoh.co.jp/tech/details/15709/)

---

出典: [ガベージコレクション（garbage collection）とは？仕組み・アルゴリズム・言語別の違いとGCログの見方](<https://www.issoh.co.jp/tech/details/3366/>)（株式会社一創）
