「Javaでなぜつくるのか」読了です

Javaでなぜつくるのか
http://amzn.to/ogo3R4

この本を読むと、Javaで何か作りたくなる

3章までは、要は「Javaがなんですごいって、JVMのおかげで、すべてのハードウェアと、すべてのOS上で、同じように動くから」ということを詳しく述べている。

5章のメモリー管理のところが、とても良いと思ったので、備忘メモ:

机の上をメモリーに見立てて:
・プログラム領域(コードセグメント)
・スタック領域(スタックセグメント)
・ヒープ領域(データセグメント)
の3つの領域がある。

1.CPUはプログラム領域に置いてある手順書(プログラム)に書かれた処理を実行する。
2.処理の途中で、サブルーチンコール(メソッドの呼び出し)によって、別の手順書に飛ぶことがある。
3.そのとき、そこまでの作業状況(どこまで処理したか=戻りアドレス、状態がどうか=レジスタの値)を「覚え書き」にメモする。この「覚え書き」をスタック領域に置く。
4.次の手順書でも、また別の手順書に飛ばされることはある。すると、また新しく「覚え書き」を作成して、スタック領域に加える。
5.ひとつ手順書を終えると、前の手順書に戻る(return)。そのとき、「覚え書き」を見て、どういう状態だったかを思い出す(=レジスタなどのリストア)
6.例えば、呼ばれた手順書に戻り値があって、その結果を前の手順書に手渡す場合は、覚え書きを経由して書き込む。
7.覚え書きはいらなくなると捨ててしまう
8.(ちなみに、このようにスタック領域に置かれている「覚え書き」はメソッドを呼び出すたびに増えて、戻るたびに減る。これが「スタック(積み重ね)」という名前の由来

ここからはヒープ領域の話
9.手順書(プログラム)には、「これから、これだけのデータを使うので、確保してください」と書いてある
10.これは、ヒープ領域に、A4の紙を置くスペースを確保してください、というような意味である

*なお、スタックには、メソッド呼び出しなどのとき、最低限必要なデータの領域を確保する。ただ、メソッドを終了しても使えるようにできない、また、大量のデータは扱いにくい
ヒープは、もっと大きなメモリ空間で、必要な量を要求して使うことができる。
C言語では、mallocでヒープ領域を確保する

以上を前提に、Cプログラムでのメモリー内の動きを見てみる:

ppersons[0].name = "佐藤"

まず「佐藤」という文字列は、プログラム領域のプログラムモジュールの内部に作られる
そして、それをポインタで指し示すことができ、この例だとppersons配列のnameのところに名前へのポインタが格納されている(ちなみに配列はヒープ領域にmalloc関数で確保)
さらに、ppersonsというポインタ変数は、スタック領域から、配列を参照している。つまり、この宣言がされているメソッドを抜けるときに、削除される。次のメソッドで使う必要があるときは、returnによって、受け渡す必要がある

以上は、かなり細かい話だが、C言語などJava以前より前の言語では、このようにヒープ領域をプログラマが自分で確保したり、解法開放したりしていた。すると
・メモリーリーク(本当は使っていない場所が机の上に残されてしまう)
・領域破壊(メモリー上のデータを間違って上書きしてしまう)
などの問題が起きやすかった
・配列・構造体、というメモリー上に置かれているデータの配置を意識しなければならなかった

Javaの解決方法:「参照」
Javaではポインタを使わず、「参照」というやり方をとっている
・したがって、Javaでは、メモリーにアクセスするコードを書くことができない
・参照とポインタの違い:
1.参照は、ポインタのようにプログラムから直接操作できない
2.型の検査をコンパイラや実行環境(JVM)が厳密に行う
3.参照型は、ポインタのように計算することはできない

・参照型と参照値
・参照値とは、オブジェクト(インスタンス)の位置(アドレス)を指し示す値で、参照型変数に代入できる
たとえば、personというPerson型を指し示す参照型変数があるとすると
Person person;
と宣言する
・この参照型変数は、直接操作できない、計算もできない
例 X Person person = (Person)5000;
X person += 2000;
・型の検査を厳密にするので、Personクラスようの参照型変数に、String型の参照値を代入することはできない(キャストできない)
例 X Person person = new String("佐藤");

Personのインスタンスを1つ生成するとは、どういうことか:
Person p = new Person("佐藤", 25);

1.Person型のインスタンス変数が必要とするバイト数の領域をヒープ領域に確保して、全体のオブジェクトリストに接続する
2.オブジェクトの参照値を仮想変数「this」に代入して、Stringと数値を引数に持つPersonクラスのコンストラクタを呼び出す(プログラム領域)
3.このポインタを参照型変数「p」に代入する(スタック領域)

Javaでは、すべてのオブジェクトをヒープに置く
 ヒープ領域を勝手に確保・解放することはできず、唯一の手段は、オブジェクト(インスタンス)を生成することだけ
 別の言い方=ヒープ上に、オブジェクト以外のものを置くことができない
ガベージコレクション
 ヒープに確保されるのは、new命令で作られるオブジェクトや配列。これらはアプリケーションから使われるとき、必ず「参照」によって結び付けられている
 どこからも参照されていないオブジェクトや配列は絶対に使えない(=使っていないということになる)
 スタックに作られる参照型変数はスコープから抜ける時点で自動的に削除され、参照型変数につけられただけのオブジェクトは自動的にガベージコレクションが回収してくれる
 メモリーリーク問題をこうやってJavaは解決している

Javaの配列の説明:
Javaではオブジェクトを直接メモリー上に並べる配列を作れない
・配列はすべての配列要素を、参照を介してアクセスする形をとる

p203の図がキモか
まず、参照型変数がスタック領域にあって、→ヒープ領域の配列オブジェクト(配列もオブジェクト)を参照→それぞれの配列が、プログラム領域のString文字を参照