
図で理解する! プログラミング言語とインフラでのインスタンスって?
インスタンスとは、IT業界では「実際に作られた何か、動いている何か」を指す言葉です。普通の日本語の文章ではまず見ないカタカナ語なので、初めて聞いた時は誰でも「?」でしょう。
「インスタンス」を特によく使うのは、プログラマとインフラエンジニアです。用途は、プログラマはオブジェクト指向の用語として、インフラエンジニアはサーバやミドルウェア、サービスの用語としてです。
そのように、プログラマとインフラエンジニアでは「インスタンス」が指しているモノや意味が違うので、両名が顔を合わせて会話すると「えっ?」となることも。
この記事では、そんなITの現場ではよく使われるけれども、少し意味の分かりづらい言葉「インスタンス」について、プログラミングやインフラの初心者にもわかりやすくお伝えします。
1.インスタンスとはどこかで実体化しているモノのこと
プログラミング言語でもインフラの領域でも、インスタンスは何らかの具体的なモノ、動いているモノ・動かせるモノです。さらにインスタンスは、何らかの手段で出現し、適切なタイミングや手段で消滅するモノです。
インスタンスは、英語だと instance と書き、意味は「例、実例、事例、実証、場合、事実、段階」(Weblio英和辞典)などです。プログラミング言語やインフラの領域では、実体(substance、entity)が最も近いと感じます。
オブジェクト指向プログラミング言語でのインスタンスは、クラスをひな形に作られて、メモリ上に存在するモノです。インスタンスこそが、データを保持したり、処理を動かす実体です。つまり、インスタンスの集まりや関係性がプログラムだとも言えます。
インフラの領域でのインスタンスは、クラウドサービス上での仮想サーバ、データベースなどのミドルウェア、それらをまとめたサービスなどの動いている実体です。これらは、必要に応じて作って起動し、必要なくなったら停止したり削除するモノです。
と、ごく簡単にインスタンスとは何かを説明してみました。もっと具体的に理解したい方は、この記事の後ろの章を読み進めていただければ、さらなる知識と理解が得られますよ。
2.プログラミング言語での「インスタンス」
プログラミング言語、特にオブジェクト指向プログラミング言語での最初の大きな壁は、クラスとインスタンスの考え方と関係性です。
クラスとインスタンスのイメージが曖昧だと、学習を進めていくにつれ、プログラムがだんだんわからなくなってきます。だからこそ、学習の早いうちに明確なイメージを持っておきたいです。
この章では、オブジェクト指向プログラミング言語でのインスタンスについて、例を交えながら説明していきます。
2-1.クラスをひな型にしてメモリ上に実体化したモノのこと
インスタンスとは、クラスをひな型にしてメモリ上に実体化したモノのことです。…と教科書的に書きましたが、これで分かれば苦労はぜんぜんありませんよね。
クラスとインスタンスの理解のために、まずクラスとはどういうモノかのイメージをつかみましょう。その後なら、インスタンスとはどういうモノかが分かる下地ができているはずです。
でもプログラミング言語の本にあるような真面目で堅苦しい書き方だと、少し分かりづらいかもしれません。ですので、この章では「たい焼きと焼き型」で説明します。
2-2.クラスはインスタンスの形を決めるひな形
クラスとは、何を持っているのか・何ができるかを決めたモノです。言い方を少し変えれば、モノを他のモノと識別・区別するための特徴を決めたものです。
「たい焼きと焼き型」の例えでは、焼き型がクラスで、たい焼きがインスタンスです。
たい焼きの焼き型とはどんなものかと言えば、鯛の形をした金属板です。頭や背びれや胸びれや尾びれ、うろこを形作るデコボコがあります。そして、ある一つの焼き型を使えば、同じ形のたい焼きが次々と焼きあがります。
つまり焼き型こそが、たい焼きの「形」を決めている「ひな形」です。焼き型はあくまで型でしかなく、たい焼きそのものと見間違える人はいません。でも、どんなたい焼きができるかは、焼き型を見れば分かりますよね。
これがオブジェクト指向での、クラスというモノの考え方の一側面です。他によく使われるのは、クラスを設計図に例えるものです。設計図も「こういうことができるものですよ」と決めたもので、設計図を基に製品を作りますよね。
2-3.インスタンスは個性を持ち区別できる実体
そんなたい焼きの焼き型を使うと、同じ形のたい焼きがどんどん焼きあがります。その一つ一つのたい焼きこそが、たい焼きのインスタンスだと言えます。
ここで当たり前のようでいて実は大事なのは、それらのたい焼きはすべて「違う」モノであること。例えば、一つの焼き型で二つたい焼きを作ったなら、見た目は同じで中身も同じつぶあんのたい焼きでも、「違う」たい焼きですよね。
そして、一つの焼き型を使っても、それぞれのたい焼きは中身を変えられます。お客様からの注文次第で、つぶあんでも抹茶あんでも何でもありです。でも、同じ焼き型から作ったたい焼きなので、見た目はすべて同じです。
つまり、何かのクラスのインスタンスは、同じクラスから作られて、すべて同じ特徴を持ちます。ですが、実体としてはすべて違っていて識別・区別できます。さらに、インスタンスごとに固有のデータを持たせられます。
インスタンスの区別については、以下の記事も参考にしてください。対象はJavaですが、他のプログラミング言語でも、似たような考え方のはずです。
関連記事なお、クラスからインスタンスを作ることを「インスタンス化(instantiation)」とも呼びます。プログラマがよく使う言葉なので、ぜひ覚えておきましょう。
2-4.インスタンスこそが、属性を持ち、操作を行う実体
前述のとおり、クラスとは、何を持ち何ができるかを決めているモノです。でも、クラスが実際に何かを持っていたり、行いはしません。それらはクラスから作られたインスタンスの役割です。
例として、今この記事を書いているのは、記事のライターである私自身です。ライターはペンネームを持ち(私は本名ですが)、記事を書けます。ここで、ライターがクラス、私がライターのインスタンスだとも考えられます。
そして、このENGINEER.CLUBには私の他にもライターがいます。彼らもライターですから、それぞれのペンネームを持ち、それぞれの流儀で記事を書きます。つまり、私も彼らも全員がライターという種類(=クラス)の人間であり、ライターのインスタンスです。
オブジェクト指向の言葉では、ライターでのペンネームが属性(attribute)、記事を書く操作がメソッド(method)です。たい焼きでは、中身が属性です。属性はインスタンスフィールドやインスタンス変数とも呼び、インスタンスのメソッドだと明確にするならインスタンスメソッドと呼びます。
ですから、ライターのインスタンスである私は「記事を書く」メソッドを持ち、それを誰かが呼び出せば、私が行った作業の結果として記事が生まれます。この記事を書いたのは、ライターという「抽象的な誰か」ではなく、「具体的な私」なのです。
2-5.【参考】オブジェクトはインスタンスより広いモノ
インスタンスとオブジェクト(Object)はよく混同されます。広く合意された定義はありませんが、よく見られるのは、オブジェクトはインスタンスよりもずっと広い意味で何かのモノを指す概念だ、というものです。
ここまでお伝えしてきたとおり、インスタンスとはクラスがインスタンス化したモノで、オブジェクトの一種です。ですが、プログラミング言語ではインスタンス以外にもいろいろなモノが出てきます。それらをひとまとめにオブジェクトと呼びます。
例えば、Javaでは3.14やtrueなどの値は、何かのクラスのインスタンスではなく、値そのものです。クラス自身も、Javaではstaticメソッドなどを持つ具体的なモノではあります。でもそれらをインスタンスと呼ぶのは変なので、そういうモノたちをオブジェクトと呼んでいます。
2-6.クラスとインスタンスの例(Java)
ここまでで、インスタンスというモノのイメージが何となくでも掴めたでしょうか。ここでは、Javaを使ってクラスとインスタンスの例を示してみます。
2-6-1.たい焼きクラスを作る
まずは、たい焼きクラス(Taiyaki)を作ります。このクラスの定義こそが、たい焼きの焼き型に相当するものです。
たい焼きには中身がありますよね(皮だけだとさみしい…)。ですから、中身を後から確認できるよう、Taiyakiクラスにnakamiという、文字列(String)のインスタンス変数を持たせておきました。
そして、このたい焼きは世にも不思議なたい焼きで、自分の中身が何であるかしゃべって教えてくれます。それを shaberu というメソッドにしてみました。
package jp.engineer_club.instance; class Taiyaki { final String nakami; Taiyaki(String nakami) { this.nakami = nakami; } void shaberu() { System.out.println(nakami + "でーす"); } }
2-6-2.たい焼きクラスからインスタンスを作る
Javaでクラスからインスタンスを作る時にはnew演算子を使います。new演算子の後ろにクラス名が続き、戻り値はインスタンスです。パラメータも必要なら渡せます。
では、この焼き型を使ってたい焼きを焼いてみます。たい焼きを焼くのはたい焼き屋さんです(Taiyakiya)。一度に三つ、つぶあんと抹茶あんで焼いちゃいます。
newすると、インスタンスがJavaのメモリ中にひょっこり出現します。それらのインスタンスを、Taiyaki型の変数(tubuan1、tubuan2、matcha)がそれぞれ指している状態になります。
そして、たい焼きのインスタンスを作る時のパラメータとして、それぞれのたい焼きの中身(つぶあん、抹茶あん)を文字列で渡しています。
package jp.engineer_club.instance; class Taiyakiya { public static void main(String[] args) { Taiyaki tubuan1 = new Taiyaki("つぶあん"); Taiyaki tubuan2 = new Taiyaki("つぶあん"); Taiyaki matcha = new Taiyaki("抹茶あん"); System.out.println("tubuan1の中身 = " + tubuan1.nakami); // → "つぶあん" System.out.println("tubuan2の中身 = " + tubuan2.nakami); // → "つぶあん" System.out.println("matchaの中身 = " + matcha.nakami); // → "抹茶あん" tubuan1.shaberu(); // → "つぶあんでーす" tubuan2.shaberu(); // → "つぶあんでーす" matcha.shaberu(); // → "抹茶あんでーす" } }
それぞれのたい焼きの「中身」は、きちんと設定されていますね。つぶあんを入れたものは“つぶあん“ですし、抹茶あんを入れたものは“抹茶あん“です。そして、同じつぶあんのたい焼きであっても、tubuan1とtubuan2は違うモノです。
2-6-3.インスタンスを指し示すのが参照型変数
前節で「インスタンスを変数が指す」と書きました。この短い文章の意味を正確に理解できているかが、ものすごく大事です。その理解があって初めて、インスタンスとはどんなものかや、インスタンスと変数の関係が分かるのです。
このたい焼きの例で、それぞれの変数がどのインスタンスを指しているかを図示すると、以下となります。
このように、変数がインスタンスを指す…少し難しい言葉を使えば参照(reference)しているのです。このような変数を、参照型変数(reference variable)と呼びます。
ちなみに参照型変数は、Javaで二種類ある変数の片方で、もう片方は基本データ型変数(プリミティブ型変数)です。
2-6-4.変数が指すインスタンスが同じか調べてみる
Javaには、変数同士が指すインスタンスが同じか調べる演算子があります。それが比較演算子(==)です。比較演算子の戻り値は、変数同士が指すのが同じインスタンスならtrue、違えばfalseです。
では、それぞれの変数が指すたい焼きのインスタンスが同じか、調べてみましょう。
package jp.engineer_club.instance; class Taiyakiya { public static void main(String[] args) { Taiyaki tubuan1 = new Taiyaki("つぶあん"); Taiyaki tubuan2 = new Taiyaki("つぶあん"); Taiyaki matcha = new Taiyaki("抹茶あん"); // 違う変数同士で調べるとfalse System.out.println(tubuan1 == tubuan2); // → false、違う System.out.println(tubuan2 == matcha); // → false、違う System.out.println(tubuan1 == matcha); // → false、違う // 同じ変数同士で調べるとtrue System.out.println(tubuan1 == tubuan1); // → true、同じ System.out.println(tubuan2 == tubuan2); // → true、同じ System.out.println(matcha == matcha); // → true、同じ } }
違う変数同士で調べたら、全部違うインスタンスを指しているとJavaは言っていますね。中身が同じつぶあんのtubuan1とtubuan2も、違うインスタンスだそうです。これが、インスタンスはすべて違うモノだということです。
そして同じ変数同士で調べたら、同じインスタンスを指しているとJavaは言っています。同じ変数同士で調べたら同じなのは当たり前、そう思われるかもしれません。ですが、これこそが実に大事なことなのです。
ここで、比較演算子(==)を使った比較は以下のように行われます。これで、変数とインスタンスの関係が分かったでしょうか。
なお、Javaではインスタンスの識別に使えるID(ハッシュコード値)を取得するには、System.identityHashCode(Object)が使えます。例えば以下のように使います。これでも、変数が指すのはすべて違うインスタンスだと分かります。
package jp.engineer_club.instance; class Taiyakiya { public static void main(String[] args) { Taiyaki tubuan1 = new Taiyaki("つぶあん"); Taiyaki tubuan2 = new Taiyaki("つぶあん"); Taiyaki matcha = new Taiyaki("抹茶あん"); // ぜんぶ違う数字なので、違うインスタンスだと分かる System.out.println(System.identityHashCode(tubuan1)); // → 943010986 System.out.println(System.identityHashCode(tubuan2)); // → 1807837413 System.out.println(System.identityHashCode(matcha)); // → 2066940133 } }
2-6-5.参照型変数が指すインスタンスは後から変えられる
なお、変数がどのインスタンスを指すかは、自由に変えられます。例えば、以下のようにやると、変数tubuan1、tubuan2、matchaが指すインスタンスがすべて同じになるのです。
package jp.engineer_club.instance; class Taiyakiya { public static void main(String[] args) { Taiyaki tubuan1 = new Taiyaki("普通なつぶあん"); Taiyaki tubuan2 = new Taiyaki("甘さ控えめつぶあん"); Taiyaki matcha = new Taiyaki("抹茶あん"); tubuan2 = tubuan1; // tubuan2が指すインスタンスをtubuan1と同じにして、 matcha = tubuan2; // matchaが指すインスタンスもtubuan2と同じにすると… // すべての変数が、同じインスタンスを指すのですべてtrue System.out.println(tubuan1 == tubuan2); // → true System.out.println(tubuan2 == matcha); // → true System.out.println(tubuan1 == matcha); // → true // すべての変数が指すのはすべて同じインスタンスなので、中身も同じ System.out.println("tubuan1の中身 = " + tubuan1.nakami); // → "普通なつぶあん" System.out.println("tubuan2の中身 = " + tubuan2.nakami); // → "普通なつぶあん" System.out.println("matchaの中身 = " + matcha.nakami); // → "普通なつぶあん" // 同様に、メソッドも同じインスタンスのものが呼ばれる tubuan1.shaberu(); // → "普通なつぶあんでーす" tubuan2.shaberu(); // → "普通なつぶあんでーす" matcha.shaberu(); // → "普通なつぶあんでーす" // インスタンスのハッシュコードも全部同じになる System.out.println(System.identityHashCode(tubuan1)); // → 943010986 System.out.println(System.identityHashCode(tubuan2)); // → 943010986 System.out.println(System.identityHashCode(matcha)); // → 943010986 } }
つまり、Javaでの参照型変数同士での代入とは、代入元の変数(右辺値)が指すインスタンスを、代入先の変数(左辺値)も指すようにすることなのです。
2-6-6.インスタンスがメモリから削除されるタイミング
以下のように、作ったインスタンスを変数で参照しないなら、たい焼きは全部ごみ箱直行です。これはJavaではコンパイルエラーにはならず、実行時エラーにもなりません。単にインスタンスを作って捨てているだけです。
package jp.engineer_club.instance; class Taiyakiya { public static void main(String[] args) { new Taiyaki("つぶあん"); new Taiyaki("つぶあん"); new Taiyaki("抹茶あん"); } }
こういうどこからも参照されていないインスタンスは、Javaなどのプログラミング言語の処理系が、メモリから自動的に削除します。どこからもインスタンスへの働きかけができないので、メモリにいるだけ無駄だからです。
この仕組みを、一般にはガベージコレクション(ゴミ集め)と呼びます。プログラマがガベコレと言う時は、このことを指しています。
もし、Javaでメモリ中にどのようなインスタンスがあるのか知りたい場合は、ヒープダンプというものを取得すると確認できます。興味があれば、ぜひ調べてみてください。「こんなにたくさんのインスタンスがあるのか!」とびっくりしますよ。
3.インフラの領域での「インスタンス」
インフラの領域では、いろいろなモノを指して「インスタンス」と呼びます。ですので、ここではインスタンスと言われる代表的なものをいくつかご紹介します。
3-1.インスタンスは実際に動いているナニカのこと
例えば、インフラエンジニアが「WEBサーバが稼働している」と言う場合、具体的にはどんな状態のことでしょうか。それにごく簡単に答えるなら、以下となります。
- サーバが電源オンの状態で、ネットワークにもつながっている
- サーバでオペレーティングシステム(OS、WindowsやLinuxなど)が動作している
- OS上で、HTTPサーバ(Apache、Nginxなど)のプログラム(プロセス)が動いていて、外部からのHTTP接続要求に応答できる
- それらのWEBサーバ群がミドルウェアによるクラスタ環境下で稼働している
インフラエンジニアの文脈で「インスタンス」と言う時は、1~4のどれか、あるいはそれらすべてを含めた範囲の中で、動いている何かしらのモノを指しています。
ずいぶん乱暴な定義だと感じられるかもしれません。しかし、どの領域で使われているかで「インスタンス」が指すモノが違うのは事実です。インスタンスとは、このようにあいまいな言葉なのです。
3-2.仮想マシンのインスタンス
サーバの構築・運用が主な仕事のインフラエンジニアが使う「インスタンス」は、クラウドサービスや仮想化環境で動いている、仮想マシンや仮想サーバを指すことが多いです。
インスタンスとそのまま呼ぶ場合は、まさに「動いている最中」の仮想マシンです。「停止中のインスタンス」は今は動いていない仮想マシンですし、仮想マシンのイメージファイルはインスタンスをファイルに出力したもののことです。
この文脈では以下のように使います。なお、クラウドサービスの課金額は稼働中のインスタンスの数に依存することも多いので、そういった文脈でも出てきますね。
- (Amazon)EC2インスタンスで今使わないのは止めちゃって
- 負荷が上がりそうだから、(Azure)Functionsのインスタンス数を増やしといて
3-2-1.なぜ仮想マシンをインスタンスと呼ぶのか
仮想マシンのことをインスタンスと呼ぶのが広まった時期は、AWSやAzureに代表される、クラウド上の仮想化環境での運用が当たり前になってからだと感じます。
少し前までは、コンピュータやサーバのことをインスタンスとは呼びませんでした。それに、データセンターに置かれている物理マシンは、今でもインスタンスとは呼ばないのが普通でしょう。
今全盛のクラウドサービスは、仮想化環境でのサーバ機能の提供から始まり、それがサービスの主力であり続けています。そこでの「インスタンス」は仮想マシンを指す用語なので、それがデファクトスタンダードになったのでしょう。
ちなみに、インスタンスという用語なのは、プログラミング言語のところでも触れた「必要に応じてお手軽に作って削除できるモノ」のイメージからでしょうか。物理サーバではそうは行きませんしね。
3-3.データベースや仮想化環境などのサーバ・ミドルウェア製品のインスタンス
サーバ・ミドルウェア製品で、OS上で動いているプログラムやWindows/Linuxなどでのいわゆるサービスを「インスタンス」と呼ぶこともあります。例えば、データベースや仮想化環境、ジョブ制御やクラスタミドルウェアなどです。
この文脈でのインスタンスは、それらのプログラムがメモリ上に読み込まれて実行中の状態を指すことが普通でしょう。OS上にインストールされているサーバ・ミドルウェアの実行ファイルなどをインスタンスとはあまり呼びません。
こちらの意味でのインスタンスの使い方には、以下のものがあります。
- (Oracleの)○○データベースのインスタンスが起動してないぞ!!
- (VMWareの)vCenter Serverのインスタンスを追加しないと、今以上の仮想マシン数は扱えませんよ
3-3-1.インスタンスは製品・ベンダごとに意味が違う
ここで知っておきたいのは、製品やベンダごとに「インスタンス」とは何か、何を指すかが、正式な用語としてあることです。
ですから、製品のマニュアルやドキュメントを読み込まないと、その文脈でのインスタンスが何かが分かりません。インスタンス数がライセンスや課金の単位であるのも普通ですから、正確な理解が必要です。
他のエンジニアやサポート窓口との会話で「うまく伝わらない」と感じたなら、それが原因かもしれませんね。分かりづらさの原因は、それらの製品が大抵は海外製なのも一因でしょうか。
3-3-2.例:Oracle Database・SQL Serverでのインスタンス
例えば、有名なデータベースのOracle DatabaseやSQL Serverでのインスタンスは、おおざっぱに言えばOS上で稼働中のデータベース環境を指します。
でも、それぞれインスタンスの定義が違います。Oracle Databaseは1インスタンスでは1データベースのみ動かしますが、SQL Serverは1インスタンスで複数データベースを動かせる…などです。
3-4.その他のインスタンス
何かのサービスをインスタンスと呼ぶこともあります。例えば、マストドン(Mastodon)という分散型SNSでは、ユーザはインスタンスという単位でサービスを使い分けます。そのインスタンスを構成するのは、インターネット上にある複数のコンピュータです。
時には、マルチインスタンスという言葉を目にするかもしれません。一般には、一つのインスタンスでは処理が追いつかない場合に、複数のインスタンスを並列で動かして、処理性能を稼ぐやり方のことです。
このようにいろいろな使われ方がされます。共通しているのは、動いている何かということです。
4.まとめ
インスタンスとは何かの実体です。いろいろなところで使われる言葉のインスタンスですが、動いているモノだというのは大体共通しています。
オブジェクト指向プログラミング言語ではクラスから作られてメモリ上で動いているモノ、インフラの領域では動いている状態のサーバやソフトウェアを指すことが普通です。
インスタンスは、正直なところエンジニア自身も、何となくとかニュアンスで使うことが多い言葉です。ですので、文脈を上手に読んで、何を指しているのか想像しながら使っていきましょう。
コメント