OS とソフトウェア

INPUT · スライド

メモリの足りなさをごまかす

01 / 12

メモリより大きいプログラムが動く

スマホのメモリが 4G バイトなのに、20G バイトのゲームが動く。おかしいと思わないかな。

プログラム全体をメモリに載せる必要はないからだよ。いま実行している場所と、いま使っているデータだけがメモリにいれば、残りはストレージで待っていてもいい。

この「載せておく分を選んで、必要になったら入れ替える」仕事をしているのが OS だよ。このレッスンで見ていくのは、その入れ替えのやり方と、そのために OS が持っている仕掛けだよ。

スマホのメモリ  4G遊ぶゲーム      20G→ 全部載せてはいない

02 / 12

主記憶を区画に分けると細切れになる

まず仮想記憶が無かった時代の話から。主記憶を区画に区切って、プログラムを1つずつそこに置いていた。

区切り方は2通りあるよ。

  • 固定区画方式 … あらかじめ決めた大きさに区切る。小さいプログラムを置くと余りが無駄になる
  • 可変区画方式 … プログラムの大きさぴったりに区切る。無駄は少ないが、置いたり外したりを繰り返すとすき間だらけになる

この「細切れの空き領域がたくさんできてしまう」現象が フラグメンテーション(断片化)だよ。空きの合計は足りているのに、連続した領域が取れないのでプログラムを置けない、という困り方をする。

散らばった中身を片側に寄せ集めて、空きを1つの大きな塊にまとめ直すのが コンパクション(メモリコンパクション)。フラグメンテーションが症状で、コンパクションが手当てという関係だよ。

[ A ][空き][ B ][空き]      2M         3MB が終わって空いても[ A ][空き][空き][空き] 空き計 8M / 連続は最大 3M→ 5M のプログラムが入らない

03 / 12

仮想記憶 ― 無い容量をあるように見せる

そこで考え出されたのが 仮想記憶 だよ。プログラムには「メモリはたっぷりある」といううその地図を見せて、実際には主記憶と補助記憶(ストレージ)を組み合わせてやりくりする。

  • 仮想記憶空間(仮想アドレス空間)… プログラムから見える、広いほうの地図
  • 実記憶(主記憶)… 本当に載せられる、狭いほうの場所

大事なのは、この対応づけを全部 OS がやっていること。プログラムを書く側は、仮想記憶を使うためのモジュールを組み込んだり、アプリごとに設定したりする必要がない。だから 20G バイトのゲームも、何も特別なことをせずに 4G バイトのメモリで動く。

ただし無料ではない。主記憶に載る量が少なすぎると、入れ替え作業ばかりになって遅くなる。そこは後のスライドで見るよ。

プログラム 8M主記憶     4M  → いま使う所だけ載せる  → 残りは補助記憶で待つ

04 / 12

ページング ― 固定長に切って対応づける

仮想記憶と実記憶をどう対応づけるか。いま主に使われているのが ページング方式 だよ。

やり方は単純で、仮想記憶空間と実記憶空間をどちらも同じ大きさの固定長の区画に区切り、その区画同士を対応づけて管理する。この固定長の区画を ページ と呼ぶ。

固定長にするのがミソだよ。大きさがそろっていれば、どのページをどの枠に入れても構わないので、さっきのフラグメンテーションが起きない。「ちょうど入る場所を探す」必要が無くなるんだ。

対応の表は ページテーブル に持っていて、仮想アドレスから実アドレスを引くのに使う。実記憶に入っていないページは「補助記憶のどこにあるか」が書いてあるよ。

仮想記憶(大きい) P0 P1 P2 P3 P4 P5  ↓  ↓  ↓        ↓実記憶(小さい) [P1][P5][P0][P3]P2 P4 は補助記憶で待つ

05 / 12

ページフォールト ― 手元に無いページを呼ぶ

プログラムがあるアドレスを触ろうとしたとき、そのページが実記憶に載っていないことがある。このとき起きるのが ページフォールト だよ。

起きたあとの流れはこうなる。

  • OS に制御が移る(割込みが入る)
  • 必要なページを補助記憶から実記憶に読み込む(ページイン
  • 空きが無ければ、どれかを追い出して場所を作る(ページアウト
  • もとの命令を実行し直す

つまりページフォールトが起きるのは、主記憶に存在しないページへアクセスしたとき。主記憶にちゃんと載っているページを何回触っても、長い間触っていなかったページを触っても、それ自体では起きないよ。載っているかどうかだけが条件だ。

補助記憶の読み書きは主記憶より桁違いに遅いので、ページフォールトが増えるとそのままスループットの低下になる。

使いたいページ  ├ 実記憶にある → そのまま  └ 無い → ページフォールト  ページイン / ページアウト

06 / 12

どのページを追い出すか

実記憶がいっぱいのときは、誰かを追い出さないと新しいページを入れられない。その選び方が ページ置換えアルゴリズム だよ。

試験に出るのは主に2つ。

  • FIFO(First In First Out)… 入ってきた順に追い出す。実記憶にいちばん長く居座っているページが出ていく
  • LRU(Least Recently Used)… 最後に参照されてから、いちばん長い時間が経ったページを追い出す

LRU の言い回しはひっかけが多いので、正確に押さえよう。見るのは「最後に使った時刻」だよ。入ってきた時刻ではない(それは FIFO)。使った回数でもない(それは LFU)。

「一定時間参照されていない」もよく並ぶけれど、これも違う。LRU は時間のしきい値で決めるのではなく、候補の中でいちばん古いものを選ぶ方式だよ。

FIFO … 入った順に追い出すLRU  … 最後に使ってから       いちばん経った物LFU  … 使った回数が最少

07 / 12

LRU を手で追いかける

計算問題は、枠の中身を「古い順」に並べたメモを1行ずつ書き足すだけで解ける。表を書くのを面倒がって暗算すると、まず間違うよ。

手順はこれだけ。

  • 参照したページが枠にあれば「当り」。その番号をいちばん新しい位置へ動かす
  • 無ければ枠に足す。枠が埋まっていればいちばん古い位置のページを追い出す

枠が4つで 1,2,3,4,5,2,1,3,2,6 を触ったときを追ってみよう。左が古い側だよ。

最後に 6 を触る時点で、いちばん古い位置にいるのは 5。5 は途中で1回も参照し直されていないから、2 や 1 や 3 に次々と抜かされてしまったんだ。

枠4 / 1 2 3 4 5 2 1 3 2 61  [1]2  [1 2]3  [1 2 3]4  [1 2 3 4]5  [2 3 4 5]  1 を追出2  [3 4 5 2]  当り1  [4 5 2 1]  3 を追出3  [5 2 1 3]  4 を追出2  [5 1 3 2]  当り6  ← いちばん古い 5

08 / 12

スラッシング ― 追い出しばかりになる

同時に動かすプログラムの数(多重度)を増やすと、1つあたりに配れるページ枠が減る。減りすぎると、入れたページがすぐ追い出され、また読み込まれ、という往復ばかりになる。

この状態が スラッシング だよ。ページイン・ページアウトが多発して、処理時間のほとんどが入れ替え作業に費やされる。OS の仕事(オーバヘッド)だけが増えて、アプリのプロセッサ使用率はむしろ下がり、応答が急激に遅くなる。

仕事を増やしたのに成果が減るので、直感に反して見えるところが問われやすい。多重度を上げるほど速くなる、とは限らない

名前が並ぶ仲間と区別しておこう。

  • メモリリーク … 確保した主記憶が解放されないままになるバグ。使える領域がじりじり減る
  • オーバレイ … プログラム領域に制限があるとき、必要になったモジュールだけを主記憶に取り込む手法
  • ロールアウト … 動いているプログラムをまるごと補助記憶へ退避させること
多重度を上げる → 1つあたりの枠が減る → ページフォールト増 → 追い出し作業ばかり → スラッシング

09 / 12

ファイルは木のかたちで置く

ここからは補助記憶側の話。ファイルを整理して置くための仕組みが ファイルシステム で、その骨格はだよ。

枝分かれの節が ディレクトリ(フォルダ)。名前に決まりがあるものを3つ覚えよう。

  • ルートディレクトリ … 木のいちばん根元。/ ひとつで表す、階層全体の最上位
  • ホームディレクトリ … 利用者ひとりに割り当てられた持ち場。その人がファイルを置くのに使う階層の最上位
  • カレントディレクトリ … いま立っている場所。CLI コースで cd で移動していたのがこれ

ルートとホームの違いに気をつけて。ルートはシステム全体の最上位、ホームは「その利用者が使える範囲での」最上位。一般の利用者はルートに勝手に書き込めないので、ls して回るのはたいていホームの中だよ。

/            ルート├ home│  └ manabiya  ← ホーム└ etc

10 / 12

絶対パスと相対パス

ファイルの場所を書き表す道順が パス で、書き方は2つあるよ。

  • 絶対パスルートディレクトリから対象までの道順。どこから見ても同じ文字列になる
  • 相対パスカレントディレクトリから対象までの道順。立っている場所が変わると書き方も変わる

絶対パスの定義は「ルートから」だよ。「カレントから」は相対パス、「ホームから」も、いちばん短いものを選ぶ、も違う。

相対パスで使う記号は2つ。. がいまここ、.. が1つ上.. を並べれば並べただけ上へ登れる。

計算のコツは、カレントディレクトリを紙に書いて、.. の数だけ右から消すこと。残った先に、後ろの道順をつなげれば絶対パスになるよ。

試験では区切りを / ではなく ¥ で書く問題も出るけれど、考え方は同じだよ。

いま /home/manabiya/work絶対 /home/manabiya/memo相対 ../memo     .  … いまここ     .. … 1つ上

11 / 12

バックアップの3つの取り方

壊れたときに戻せるように控えを取るのがバックアップ。取り方は3つあるよ。

  • フルバックアップ … 毎回すべてのファイルを取る。時間と容量を食うが、戻すのは1本で済む
  • 差分バックアップ前回のフルバックアップ以降に変わったファイルを取る
  • 増分バックアップ直前に行ったバックアップ以降に変わったファイルだけを取る

差分と増分の違いは、どこを起点にするかだけ。差分は毎回フルの時点から数えるので、日が経つほど1回のバックアップが太っていく。増分は前回からの分だけなので毎回細いままだよ。

そのぶん、戻すときの手間が逆になる。差分はフル+最新の差分の2本で戻せるが、増分はフル+その後の増分を全部、順番に適用しないと戻せない。取るのが速いほうが、戻すのは遅いんだ。

OS はファイルごとに「前回のバックアップ以降に更新された」という印を持っている。増分は取ったあとにこの印をリセットする。差分は次も同じ範囲を取りたいので、印をそのまま残すよ。

日 フル [======]月 増分     [+]火 増分       [+]水 差分  [+++++]戻す: 増分=日+月+火 全部      差分=日+水 だけ

12 / 12

OSS とライセンス

最後に、ソフトウェアを使う側の約束ごと。OSS(オープンソースソフトウェア)は、ソースコードが公開され、改変も再配布も許されているソフトウェアだよ。

「無料のソフト」という意味ではないところに注意。第三者が製品として再配布してよく、そのとき元の開発者はライセンス費を請求できないのが OSS の条件だよ。特定の業界だけに公開範囲を絞る、というのも OSS の定義から外れる。

ライセンスは大きく2系統ある。

  • BSD ライセンスや MIT ライセンス … 改変して組み込んでも、自分の側のソースを公開しなくてよい
  • GPL … 改変して再配布するなら、派生物も同じ条件で公開する。この考え方を コピーレフト と呼ぶ

GPL でひっかかりやすいのが範囲だよ。義務が生じるのは再配布したとき。改変したものを社内で使うだけなら、外注して作らせても、公開の義務は生じないよ。

MIT / BSD  → 公開しなくてよいGPL(コピーレフト)  → 派生物も GPL で公開