「メモリは640KiBで十分」は本当だったのか?〜メモリ管理技術の変遷を学ぶ:Windows温故知新〜カリスマITトレーナーが語る技術の変遷(6)
今、皆さんが使っているPCにメモリはどれくらい搭載されているだろうか。おそらく4GBから16GBの間ではないだろうか。しかし、1990年ごろまでのPCは1MBにも満たなかったのだ。今回は「メモリ管理技術」の歴史を紹介する。
Windows前史:8bitプロセッサから16bitプロセッサへ
個人用コンピュータの始まりは、Intelの「8080」プロセッサ(別名:i8080)とそれを利用した「Altair 8800」である(Altair 8800については本連載第2回で紹介)。
Altair 8800が発売された1974年ごろは、小型コンピュータは16bitプロセッサ、大型コンピュータは32bitプロセッサが一般的だったが、8080はコストを抑えるため、さらに低性能な8bitプロセッサだった。ただし、利用可能なメモリアドレスサイズは16bit(0〜65535番地まで)で、1アドレス当たり8bit(1byte)のデータを格納できた。つまり、最大メモリ容量は65536byte(64KiB)となる。
8080とその上位互換プロセッサであるZilog(ザイログ)の「Z80」はかなり売れ、PC用プロセッサ覇権戦争の初戦にIntelは勝利した。しかし、数年のうちに8bitプロセッサでは計算能力とメモリ容量の限界が見えてきた。
8bitプロセッサが計算できるのは、原則として8bitデータ(0〜255)に限られる。100点満点の試験を5科目集計するだけでも、何度かに分けて計算しなければならない(実際には基本的な16bit演算も可能だったのだが、ここでは感覚的に捉えてほしい)。また、64KiBの中にプログラムもデータも収めなければならないのも苦しかった。8080登場当時は2KiBとか4KiBメモリの機種もあったくらいだったので、まさか64KiBも使うとは思っていなかったのだろうが、そんな時代は一瞬で終わった。
筆者が最初に読んだコンピュータ書籍『マイ・コンピュータ入門―コンピュータはあなたにもつくれる』だったか、続編の『マイ・コンピュータをつくる―組み立てのテクニック』(いずれも1977年)だったかには、「64KiBものメモリを個人で持つことは不可能であろう」みたいなことが書いてあった。
いずれにしても、当初の予想に反して多くのメモリを利用するようになったため、Intelは次世代プロセッサとして「8086」(別名:i8086)を投入した(1978年)。8086は16bit化することで計算能力を強化し、利用可能なメモリ容量を1MiB(20bit)=1024KiBに拡大した。実際にはハードウェアの問題で、大半のPCでは640KiBしか使えなかったが、それでも8bit機の10倍である。
Microsoftの共同創業者ビル・ゲイツ氏も「640KiBは全ての人にとって未来永劫(えいごう)十分なメモリだ」と言ったとか言わなかったとか(後に64bit版Windowsを発表したころに「そんなことを言った覚えはないのだが……」と発言している)。
Windows前史:MS-DOSのメモリ管理
8086は8080と直接の互換性はないものの、アセンブリ言語レベルの互換性を持っているため、8080アプリケーションを8086用に変換するのは容易だった。しかし、その代償として64KiBを超えるメモリを扱うのが難しかった。8086をひと言で表現すると「8bit寄りの16bitプロセッサ」になる。
8086の最大の課題は、通称「64KiBの壁」だった。プログラムの実行番地を示す機能を「プログラムカウンタ」と呼ぶ。8086のプログラムカウンタは16bitしかない。メモリ領域は全部で20bitあるので、16bitでは4bit足りない。
これを補うのが16bitの「セグメントレジスタ」で、アドレスの開始番地に細工をする。具体的には、実際の有効な番地(実効番地)は、「セグメントレジスタの内容を16倍(4bitだけ左にシフト)した値」と「プログラムカウンタの値」を加算したものになる(図1)。64KiBを超えるデータを扱う場合は、セグメントレジスタの値を書き換えてからアクセスする。つまり、連続してアクセスできるのは最大で64KiBに限定される。
セグメントを使ったメモリ拡張は、当初から技術的には非常に評判が悪かったが、8086のプログラムを最小限の労力で移植できるという、ビジネス上のメリットは大きかった。「IBM PC」に採用されたこともあって、IntelはPC用プロセッサ覇権戦争の第2戦も勝利した。
Windowsのメモリ管理:セグメント方式
IBM PC(1981年)が8086の廉価版である8088を採用したこともあって、8086は大成功したが、PC利用分野が拡大するとさらに多くのメモリを使いたいという要望が高まってきた。そこで登場したプロセッサが「80286」である(1984年)。80286では利用可能な物理メモリを16MiBに拡大するとともに、仮想記憶システムも導入した。
「仮想(Virtual)」は、「実際には存在しないが、あたかもそこにあるかのように見せかける技術」である。「Virtual」の標準的な日本語訳は「事実上の」「実質的な」であって、「架空の」という意味ではない。例えば「Virtual Boss」は「AIの上司」ではなく、「正式な役職ではないが、実質的に上司の役割を果たす人(陰のボス)」になる。
80286を起動すると「8086互換モード(リアルモード)」で動作するが、途中で「プロテクトモード」に切り替えられる。プロテクトモードでは、セグメントレジスタが物理番地ではなく、「セグメントセレクタ」と呼ばれる「物理番地への変換テーブルの場所」となる(図2)。物理番地への変換テーブルを「セグメントディスクリプタ」と呼び、物理アドレスの先頭番地と長さが記載される。これにより、複数のプログラムが同時に同じメモリを参照することを防ぐ。
セグメントレジスタは相変わらず16bitだが、ディスクリプタテーブルを仲介することで、1MiBを超えるメモリアクセスができる上、8086用のアプリケーションがそのまま動作する。セグメントレジスタの内容が物理アドレスであっても、セグメントセレクタであっても、アプリケーションプログラムから見ると動作に違いはないからだ。8086設計時点でセグメント方式の仮想記憶の可能性を考えていたのかもしれない(その証拠はない)。
もっとも、80286はいったんプロテクトモードに移行すると、元のモード(リアルモード)に戻れないという致命的な欠点があった。そこで、「Windows/286」(1988年)では「リアルモードに戻すためリセット信号を出す」というトリッキーな手法が使われた。IBM PCはキーボードからリセット信号を出すことができるため、この方法が実現できたのだが、リセットしてもOSが止まらないようにするのは難しかっただろうと想像する。
ところで、こうしたリセット信号発生機能を持たないはずの「NEC PC-9801」ではどうしていたのだろう? Windows/286に相当する製品は「Windows 2.1」としてNEC PC-9801用に発売されたので(1989年)、何とかしていたと思うがよく分からない。
セグメント方式とデマンドページング方式
仮想記憶の仕組みには、大きく分けて「セグメント方式」と「デマンドページング方式」がある。どちらも利点と欠点があるが、現在の主流はデマンドページング方式である。
セグメント方式は、割り当てるメモリサイズを自由に設定できるため、メモリを無駄なく使用できる(ただし、後述するようにこれが本当に利点といえるかどうかは結構怪しい)。80286では8086のメモリ管理手法を継承し、最大サイズは64KiBである。
一方、セグメント方式の欠点は、メモリ管理の効率が悪くなることである。セグメント長は可変なので、物理メモリの割り当てに隙間ができる可能性がある。細切れのメモリばかり余っていても、大きなサイズのメモリを割り当てることはできない(図3)。
そこで、「Windows 3.0」は必要に応じてメモリ内容をコピーして、連続した空き領域を確保する機能を持っていた。この作業を「デフラグ」や「コンパクション」と呼ぶ。デフラグはなかなか「重い」処理なのに、いつ起きるか予測できず苦労したようだ。
一般にメモリ容量を節約したいのはメモリが少ないときだが、メモリが少ないとメモリ割り当ての隙間が生じやすい。つまり「物理メモリを節約できる」ことがメリットなのに、「メモリが少ないときほど無駄が出やすい」という、何とも無意味なことになってしまう。
これに対してデマンドページング方式は、物理メモリを「ページ」と呼ばれる固定長の断片に分割する。80286の後継として1985年に発表されたIntelの「i386」(旧称80386)プロセッサのページサイズは「4096byte」だ。固定長なのでメモリ割り当てには無駄が出る場合がある。
例えば、5000byteのメモリが必要だとする。1ページ4096byteでは足りないので、2ページを割り当てるのだが、2ページ目には904byteしか必要ではないため(5000−4096=904)、残りの3192byteは使われない。
しかし、デマンドページング方式ではページが連続している必要がないので、実際にはかえって無駄が減る。これは、プログラムが使っているページ(論理ページ)と、実際のメモリ上のページ(物理ページ)の割り当てを管理するテーブル(ページテーブル)を使うためである。
ページテーブルはプログラム(正確には「プロセス」)単位で作成されるものと、OSが内部で使うものがある。どちらにしてもプログラム(またはOS)が使っているメモリ領域(論理メモリ)と物理メモリをページテーブルの情報を使って対応させることで、プログラムからは連続したアドレスを使っているように見える(図4)。
デマンドページング方式のもう一つの利点は、メモリ割り当てが自由な点にある(図5)。プログラムが追加のメモリを要求したら新しいページを割り当て、ページテーブルを更新する。メモリが足りない場合は、最近使っていないメモリをファイルに退避させてメモリ領域を確保する。退避させた情報が必要になったら、ファイルから呼び戻す。
退避させる作業を「ページアウト」、呼び戻す作業を「ページイン」、両者を併せて「ページング」と呼ぶ。「デマンドページング」はメモリの要求(demand)に応じてページを割り当てるという意味である。ページングに使うファイルを「ページングファイル」または「ページファイル」と呼ぶ。
メモリ速度に比べるとファイルアクセスの速度は圧倒的に遅いため、ページングが発生すると速度が大幅に低下する。しかし、遅くても「プログラムを実行できる」というのは大きな利点である。
Windows NTのメモリ管理:デマンドページング方式
8086からの互換性を重視した80286ではセグメント方式の仮想記憶を提供したが、メモリの利用効率が悪いことから、次世代プロセッサであるi386からはデマンドページング方式も使えるようになった。
これを受けてWindows 3.0の「エンハンスドモード」では、OS内部でデマンドページング方式を使うようになったが、アプリケーションは相変わらず8086/80286のセグメントを意識する必要があった。これは主に互換性を維持するためであるが、より高機能なアプリケーションを求める声には応えられなくなってきた。
そこでMicrosoftは次世代OSとして一から「Windows NT」を開発し、1993年に公開した。Windows NTはデマンドページング方式を全面的に採用し、アプリケーションもセグメントを意識する必要はなくなった。セグメントを使っている古いWindowsのプログラムも内部でデマンドページングに変換して実行された。
デマンドページング方式は、単に物理的なメモリ番地を意識しなくてもよいだけでなく、ページングファイルを使うことで実際の物理メモリ以上のメモリを利用できるという利点がある。ただし、ページングが発生すると相当な速度低下があるので、できれば避けたい。
ページングを発生させない最も効果的な方法は、必要以上のメモリを搭載することである。Windowsで実際の使用メモリ量を確認してみよう(図6)。
1.「タスクマネージャー」を起動する
簡易表示になっている場合はウィンドウ下部の[詳細]をクリックして詳細表示に切り替える(簡易表示は「Windows 11」の新しいバージョンで廃止)
2.[パフォーマンス]タブで[メモリ]を選択する
3.画面下部の[コミット済み]を確認する
・左側(数字の小さい方):コミットメモリ量(現在使用中または使用予定のメモリ)
・右側(数字の大きい方):コミットメモリ量の上限(利用可能最大メモリ量)
コミットメモリ量よりも多くの物理メモリを搭載すると、ページングが発生しない可能性が高まる。コミットメモリにはこれから使用する予定のメモリも含まれているため、全てが実際に使用中とは限らない。しかし、コミットメモリ以上の物理メモリがあれば安心できる。
ちなみに図6内の画面は筆者の自宅PC(物理メモリ16GiB)のものなので、メモリが足りない可能性がある。詳細な調査をした結果、本当にメモリが足りないことが分かったのだが、最近メモリが高騰していてちょっと買い足す気にはなれない。
デマンドページング方式はメモリ割り当ての無駄が出るが、その無駄はせいぜい数KBである。今後もWindowsではデマンドページング方式が使われ続けるだろう。
column1:もう1つの16bitプロセッサ
8080やZ80とライバル関係にあったMotorolaは、同社の8bitプロセッサ「MC6800」やその高機能版の「MC6809」の後継として「MC68000」を発表した(1980年)。MC68000はMC6809などと互換性はなかったが、内部的には完全に32bit対応のプロセッサだった。
しかし、MC68000はAppleの「Macintosh」やSun Microsystemsなどの多くの高性能ワークステーションに採用されたものの、PC OSの主流にはならなかった。互換性がいかに大切であったかが分かる。
ちなみに、MC6800の開発者がスピンアウトして設計したプロセッサが、MOS Technologyの「6502」である。こちらは構造を簡素化することで低価格で高い性能を実現し、「Apple II」(1977年)に採用された他、派生品が任天堂「ファミリーコンピュータ」(ファミコン)に採用された(1983年)。
互換性を損ないながらも成功した例もある。「UNIX」とMacintoshである。UNIXはもともと異なるプロセッサに移植可能なことを目標に設計されたため、プロセッサが違っても比較的容易に移行できる。例えば、Sun Microsystemsは当初MC68000を使ったUNIXワークステーションを発売していたが、後に自社製の「SPARC」プロセッサに移行し、i386にも移植された。
MacintoshはMC68000からスタートし、長い間Motorolaのプロセッサを使っていたが、1991年からIBMが中心となって設計した「PowerPC」に移行後、2005年からIntelのプロセッサに移行し、さらに2020年には自社開発のプロセッサに移行している。
UNIXと違い、もともと異なるプロセッサへの移植は意識していなかったと思うが、利用者に大きな負担をかけずに何度もプロセッサを変更しているのは「ユーザーに負担をかけない」というAppleの執念を感じる。
なお、Macintoshに仮想記憶が導入されるのはかなり遅く、「System 7」(1991年)でセグメント的な考え方が部分的に導入されてからである。デマンドページング方式が採用されたのは「MacOS X」からなので2001年まで待つ必要があった。
一方、Windowsで仮想記憶が部分的に導入されたのがWindows/286(1988年)、本格的なデマンドページング方式の導入がWindows NT(1993年)なので、メモリ管理に関しては数年の差がある。
Macintoshは先進的なGUI(グラフィカルユーザーインタフェース)を持ち、ネットワーク機能が標準装備されるなど、利用者の使い勝手を良くする技術は早くから導入されたが、メモリ管理やタスク管理など、利用者が直接目に触れない部分にはそこまで力を入れていなかったのかもしれない。
column2:2進接頭辞
国際単位系(SI単位系)では、1000倍を「k」(キロ)、さらに1000倍(100万倍)を「M」(メガ)、さらに1000倍(10億倍)を「G」(ギガ)で表記する。規格ではk(キロ)は小文字と定義されているが、M(メガ)以上は全て大文字なので、それに引きずられてキロも大文字のKを使う場合もある。
コンピュータ分野では1000倍単位より「2の10乗である1024倍」を使った方が分かりやすいので「1024倍」を「k」(キロ)と称する習慣がある。1000と1024の差はわずかなので、それほど大きな問題はなかったが、値が大きくなるとその差が無視できなくなる。
そこで「2進接頭辞」(binary prefix)が定義され、1024倍を区切りとした名称が追加された。1024倍は「Ki」のように小文字の「i」を付加して「キビ」と読む(キロバイナリの意味)。さらに1024倍は「Mi」(メビ=メガバイナリ)、その1024倍は「Gi」(ギビ=ギガバイナリ)となる。なお、キロは小文字のkだが、キビは大文字のKを使って「Ki」となる。
2進接頭辞が定義されたことに伴い、1kBは1024byteではなく常に1000byteの意味になるはずだが、従来の習慣を引きずって1kBを1024byteの意味で使うことも多く、大変ややこしい。「iが付いていれば1024単位、付いていなければどちらか分からないので空気を読んで推測する」ということになる。
今回はWindowsのメモリ管理の歴史について解説した。現在はほとんどのOSでデマンドページング方式が使われており、他の方法は知る必要もないかもしれない。それでも過去にさまざまなメモリ管理の試みがあったことは知っておいていただきたい。
- 参考図書:横山哲也監修・共著『Windows Server 2003完全技術解説』日経BP(2003年)
- 参考図書:安田寿明著『マイ・コンピュータ入門―コンピュータはあなたにもつくれる』講談社ブルーバックス(1977年)
- 参考図書:安田寿明著『マイ・コンピュータをつくる―組み立てのテクニック』講談社ブルーバックス(1977年)
【主な出来事】
- 1974年 Intel 8080/Motorola MC6800/Altair 8800
- 1975年 MOS Technology 6502
- 1976年 Apple I
- 1977年 Apple II
- 1978年 Intel 8086
- 1979年 Motorola MC6809
- 1980年 Motorola MC68000
- 1981年 IBM PC
- 1982年 Intel 80286発表(出荷開始は1984年)
- 1983年 任天堂 ファミリーコンピュータ
- 1984年 Intel 80286出荷開始/Apple Macintosh
- 1985年 Intel i386(80386)/Windows 1.0
- 1988年 Windows/286
- 1989年 Windows 2.1日本語版
- 1990年 Windows 3.0
- 1993年 Windows NT
筆者紹介
横山 哲也(よこやま てつや)
トレノケート株式会社(旧グローバル ナレッジ ネットワーク株式会社)で、マイクロソフト認定トレーナーとしてMicrosoft AzureやWindows ServerなどのIT技術者向けトレーニングを担当。Windows Serverの全てのバージョンを経験。近著に『徹底攻略 Microsoft Azure Fundamentals教科書[AZ-900]対応 第2版』(インプレス)、『ストーリーで学ぶWindows Server ひとり情シスのためのITシステム構築入門』(日経BP社)がある。好きなサービスはActive Directoryドメインサービス、推しているアイドルは皆本しいね(「君のメインヒロイン」所属)。
Copyright © ITmedia, Inc. All Rights Reserved.





