web-dev-qa-db-ja.com

RAMにロードされたプロセスによってファイルが開かれていますか?

コマンド、たとえばsedはプログラムであり、プログラムはファイル内の体系化されたロジックであり、これらのファイルはハードディスクのどこかにあります。ただし、コマンドが実行されている場合、ハードディスクからのファイルのコピーが[〜#〜] ram [〜#〜]に入れられ、ここで人生と何かを行うことができますプロセスと呼ばれます。

プロセスは他のファイルを利用し、それらに読み取りまたは書き込みを行うことができます。それらが使用する場合、それらのファイルはオープンファイルと呼ばれます。実行中のすべてのプロセスによって開いているすべてのファイルを一覧表示するコマンドがあります:lsof

OK、それで私が不思議に思っているのは、コマンドの2つの寿命(1つはハードディスク上、もう1つはRAM=内)が他の種類のファイル、たとえばロジックはプログラムされていませんが、単にデータのコンテナーです。

私の想定では、プロセスによって開かれたファイルもRAMに読み込まれます。それが本当かどうかは分かりませんが、それは単なる直感です。

誰か、それを理解できますか?

25
sharkant

ただし、コマンドが実行されているときは、ハードディスクからのファイルのコピーがRAMに保存されます。

これは間違っています(一般的に)。プログラムが実行されると( execve(2) ...)プロセス(そのプログラムを実行)が 仮想アドレス空間 を変更し、カーネルが-を再構成します [〜#〜] mmu [〜#〜] その目的のため。 仮想メモリ についてもお読みください。アプリケーションプログラムは mmap(2)munmapmprotect(2) を使用して仮想アドレス空間を変更できることに注意してください (動的リンカーld-linux(8) を参照)。 madvise(2)posix_fadvise(2) および mlock(2) も参照してください。

将来の ページフォールト は、実行可能ファイルから(遅延的に)ページをロードするためにカーネルによって処理されます。 スラッシング についてもお読みください。

カーネルは大きな ページキャッシュ を維持します。 copy-on-write についてもお読みください。 readahead(2) も参照してください。

OK、それで私が不思議に思っているのは、コマンドの2つの寿命(1つはハードディスク上、もう1つはRAM=内)が他の種類のファイル、たとえばロジックはプログラムされていませんが、単にデータのコンテナーです。

システムコール の場合 read(2)write(2) のように、ページキャッシュも使用されます。読み込まれるデータがその中にある場合、ディスクIOは実行されません。ディスクIOが必要な場合、読み込まれたデータはしたがって、実際には、同じコマンドを2回実行すると、2回目にディスクへの物理I/Oが実行されない可能性があります(SSDではなく古い回転ハードディスクがある場合)。あなたはそれを聞くかもしれません;またはあなたのハードディスクLEDを注意深く観察してください)。

オペレーティングシステム:3つの簡単な小片 (無料でダウンロード可能、1つPDFファイル))のような本を読むことをお勧めします。

Linux Ate My RAM も参照して、xosviewtophtopまたはcat /proc/self/mapsまたはcat /proc/$$/mapsproc(5) を参照してください。

PS。私はLinuxに焦点を当てていますが、他のOSにも仮想メモリとページキャッシュがあります。

27

いいえ、ファイルを開いてもメモリに自動的に読み込まれるわけではありません。それはひどく非効率的でしょう。たとえば、sedは、他の多くのUnixツールと同様に、入力を1行ずつ読み取ります。現在の行以上のものをメモリに保持する必要はめったにありません。

awkの場合も同じです。一度にrecordを読み取ります。これはデフォルトでは行です。もちろん、入力データの一部を変数に格納すると、それはもちろん余分になります1

一部の人々は次のようなことをする習慣があります

_for line in $(cat file); do ...; done
_

シェルはforループの最初の繰り返しを実行する前に$(cat file)コマンド置換を完全に展開する必要があるため、これはwillfile全体をメモリに読み取ります(forループを実行するシェルが使用するメモリに)。これは少しばかげているし、エレガントでもありません。代わりに、

_while IFS= read -r line; do ...; done <file
_

これはfileを行ごとに処理します(ただし、読み取りを行います 「IFS = read -r line」 を理解しています)。

ほとんどのユーティリティはとにかく行指向なので、シェルでファイルを1行ずつ処理する必要はほとんどありません( を参照してください)シェルループを使用してテキストを処理することは悪い習慣と見なされていますか? ) 。

私はバイオインフォマティクスで働いており、大量のゲノムデータを処理する場合、絶対に必要なデータのビットのみをメモリに保持しない限り、多くのことを行うことはできません。たとえば、VCFファイルにDNAバリアントを含む1テラバイトのデータセットから個人を特定するために使用できるデータのビットを取り除く必要がある場合(そのタイプのデータは公開できないため)、1行ずつ行います単純なawkプログラムでの処理(VCF形式は行指向であるため、これは可能です)。私はしないファイルをメモリに読み込み、そこで処理し、再び書き戻します!ファイルが圧縮されている場合、zcatまたは_gzip -d -c_を介してフィードします。gzipはデータのストリーム処理を行うため、ファイル全体をメモリに読み込むこともできません。

JSONやXMLのように行指向ではないファイル形式でも、巨大なファイルをすべて保存せずに処理できるようにするストリームパーサーがあります。羊。

実行可能ファイルでは、共有ライブラリをオンデマンドでロードしたり、プロセス間で共有したりできるため、少し複雑です( 共有ライブラリのロードとRAM usage 、 例えば)。

キャッシュについては、ここでは触れていません。これは、RAMを使用して、頻繁にアクセスされるデータを保持するためのアクションです。小さなファイル(実行可能ファイルなど)は、ユーザーが多くの参照を行うことを期待して、OSによってキャッシュされる場合があります。ファイルの最初の読み取りとは別に、以降のアクセスはディスクではなくRAMに対して行われます。通常、入出力のバッファリングのようなキャッシュは、ユーザーと使用されるメモリの量に対して大部分は透過的です。キャッシュするものは、アプリケーションによって割り当てられるRAM.


1技術的には、ほとんどのプログラムはおそらく、明示的なバッファリングを使用するか、標準のI/Oライブラリが行うバッファリングを介して暗黙的に入力データのチャンクを一度に読み取り、そのチャンクを1行ずつユーザーのコードに提示します。ディスクのブロックサイズの倍数を読み取る方が、たとえば、一度にキャラクター。ただし、このチャンクサイズが数キロバイトよりも大きくなることはめったにありません。

35
Kusalananda

いいえ。RAMのギグは最近素晴らしいですが、RAMが非常に限られたリソースであるときがありました(私はVAX 11/750(2MBのRAMを搭載)およびRAMの唯一のものは、アクティブな実行可能ファイルとアクティブなプロセスのデータページ、およびバッファキャッシュにあるファイルデータでした。
バッファキャッシュがフラッシュされ、データページがスワップアウトされました。そして時々頻繁に。読み取り専用の実行可能ページが上書きされ、ページテーブルにマークが付けられたため、プログラムがそれらのページに再度アクセスした場合、ファイルシステムからページインされました。スワップからデータがページインされました。上記のように、STDIOライブラリはブロックでデータを取得し、必要に応じてプログラムによって取得されました。fgetc、fgets、freadなどです。mmapを使用すると、次のようにファイルをプロセスのアドレス空間にマッピングできます。共有ライブラリオブジェクトまたは通常のファイル。はい、RAM=であるかどうか(mlock)の場合はある程度の制御が可能ですが、それはこれまでのところです(mlockのエラーコードセクションを参照)。

5
Roger L.