高校物理160203 views
りんご209490 views
中学英語811710 views
中学理科1630641 views
LaTeX962153 views
高校化学2924392 views
ヒストリア290598 views
高校倫理1440106 views
中学社会668760 views
世界の国564520 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

ファイルを開くとき OS は何をしているのか:ファイルディスクリプタとカーネルの仕組み

Python で open() を呼んだとき、内部では何が起きているのか。「リソースを確保する」「ファイルを閉じる」とは具体的に何を意味するのか。OS とカーネルのレベルまで掘り下げて解説する。

ファイルを開くとは何か

Python の open("data.txt") は、最終的に OS のシステムコール open() を呼び出す。このシステムコールが返すのは「ファイルディスクリプタ」と呼ばれる小さな整数だ。

import os

# Python の open() が返すファイルオブジェクト
f = open("data.txt")

# その内部にあるファイルディスクリプタ(整数)
print(f.fileno())  # 例: 3

ファイルディスクリプタは、カーネルが管理するリソースへの「チケット番号」のようなものだ。プログラムはこの番号を使って「3 番のファイルから読んでくれ」とカーネルに依頼する。

カーネル内部の 3 つのテーブル

ファイルを開くと、カーネル内部で 3 つのデータ構造が関係する。

プロセスのファイルディスクリプタテーブル

各プロセスが持つテーブル。ファイルディスクリプタ(整数)から、システム全体のオープンファイルテーブルへのポインタを保持する。

システム全体のオープンファイルテーブル

カーネルが管理するテーブル。ファイルの現在位置(オフセット)、読み書きモード、参照カウントなどを保持する。

inode テーブル(vnode)

実際のファイルのメタデータ。ファイルサイズ、パーミッション、ディスク上のブロック位置などを保持する。inode はファイルシステム上の「実体」への参照。

この 3 層構造のおかげで、同じファイルを複数のプロセスが異なる位置で読み書きできる。

open() システムコールで起きること

C 言語で書くと、ファイルを開く処理は以下のようになる。

#include <fcntl.h>
#include <unistd.h>

int main() {
    // open() システムコール
    int fd = open("data.txt", O_RDONLY);
    
    // read() でデータを読む
    char buf[100];
    ssize_t n = read(fd, buf, sizeof(buf));
    
    // close() でリソースを解放
    close(fd);
    
    return 0;
}

open() が呼ばれると、カーネル内部で以下の処理が行われる。

パス名を解決して inode を特定

オープンファイルテーブルにエントリを作成

プロセスの FD テーブルに空きスロットを確保

ファイルディスクリプタ(整数)を返す

「リソース」とは何か

ファイルを開いたときに確保される「リソース」は、メモリとは異なる。

メモリ(ヒープ)

malloc() で確保、free() で解放。プロセス内で自由に使える領域。

ファイルディスクリプタ

カーネルが管理する番号。プロセスごとに上限がある(デフォルトで 1024 程度)。カーネル全体でも上限がある。

# プロセスあたりの FD 上限を確認
ulimit -n
# 1024

# システム全体の上限を確認
cat /proc/sys/fs/file-max
# 9223372036854775807

ファイルを閉じ忘れると、この「枠」を消費し続ける。大量のファイルを開いたまま放置すると「Too many open files」エラーになる。

close() で何が解放されるか

close() システムコールは以下の処理を行う。

FD テーブルのエントリを削除

プロセスのファイルディスクリプタテーブルから該当エントリを削除し、その番号を再利用可能にする。

オープンファイルテーブルの参照カウントを減らす

参照カウントがゼロになれば、オープンファイルテーブルのエントリも削除される。fork() で子プロセスと共有している場合は、両方が close() するまで残る。

inode の参照カウントを減らす

オープンファイルテーブルと同様、参照がゼロになれば inode もキャッシュから解放される可能性がある。

fork() とファイルディスクリプタ

プロセスを fork() すると、ファイルディスクリプタテーブルがコピーされる。親子は同じオープンファイルテーブルエントリを共有するため、ファイルオフセットも共有される。

int fd = open("data.txt", O_RDONLY);
pid_t pid = fork();

if (pid == 0) {
    // 子プロセス: 5 バイト読む
    char buf[5];
    read(fd, buf, 5);  // オフセットが 5 に進む
} else {
    // 親プロセス: 子の後に読むと 6 バイト目から始まる
    wait(NULL);
    char buf[5];
    read(fd, buf, 5);  // オフセット 5 から読む
}

これが「オープンファイル記述」を共有するということだ。

Python の with 文とシステムコール

Python の with 文は、最終的に close() システムコールを呼ぶ。

# これは
with open("data.txt") as f:
    data = f.read()

# 内部的にはこうなっている(簡略化)
f = open("data.txt")  # → open() システムコール
try:
    data = f.read()   # → read() システムコール
finally:
    f.close()         # → close() システムコール

with 文が保証するのは「どんな例外が起きても close() システムコールが呼ばれる」ということだ。

なぜ「閉じる」必要があるのか

ファイルを閉じないとどうなるか。

FD 枯渇

プロセスあたりの上限(通常 1024)に達すると、新しいファイルを開けなくなる。

データ未書き込み

書き込みはバッファリングされており、close() や flush() するまでディスクに書き込まれない可能性がある。

他プロセスへの影響

排他ロックを取得したまま閉じないと、他のプロセスがファイルにアクセスできない。

まとめ

Python レベル

open() でファイルオブジェクトを取得、close() で解放。with 文で自動管理。

OS レベル

システムコール open() で FD を取得、close() でカーネルのテーブルエントリを解放。FD はカーネルが管理する有限リソース。

「ファイルを開く」とは、カーネルにお願いして番号札(FD)をもらうこと。「ファイルを閉じる」とは、その番号札を返却してカーネル内のテーブルをクリーンアップすること。メモリとは異なる、OS レベルのリソース管理が行われている。