変数のメモリ管理

今回は、プログラムの変数のメモリ管理についてまとめてみる。
ここら辺は、普段プログラムを書いてる人でも、意外と知らないことがあったりするので、理解しておくとちょっと賢くなった気分になれそうですね。

基本データ型

通常のプログラム言語にある基本データ型は以下。

  • 整数型
  • 実数型
  • 文字列型
  • 論理型
  • ポインタ型(無い言語もある)

初期のプログラム言語では、整数型や実数型が何ビットで表現されるかは、マシンに依存していたが、現在は依存しないようになっている。例えば、Javaでは、以下のように決められている。

byte型 8ビット
short型 16ビット
int型 32ビット
long型 64ビット
float型 32ビットの浮動小数点表示
double型 64ビットの浮動小数点表示

配列型

要素の型がTである長さnの1次元配列Aは、T型のデータの表現に使われる記憶域がn個連続したもので表現出来る。

Fortran

例えば、Fortranでは、以下のような表現される。
名前をAとすると、先頭がA[1]、最後がA[n]である。


図1

C

Cでは、以下のように二つの要素で表現され、Aという名前は配列の先頭要素へのポインタに付いている。
Cでは、先頭がA[0]、最後がA[n-1]になる。


図2


Java

Javaでは、以下のように、配列、配列の先頭要素へのポインタ、配列の長さnで表現される。


図3



Cと同じように、先頭要素へのポインタにAという名前が付いているが、これを独立にポインタとして扱うことは出来ない。それで、Javaにはポインタが無いと言われる。


構造体

Pascalのrecord型のデータ、Cのstructを使った構造体などは、その要素(メンバー、フィールドなどと呼ばれる)のデータを1まとめにしたものとして表現される。

struct a {
    int x;
    int y;
    double z;
}


図4



また、Pascalのvariant record、Cの共用体(union)は1つの記憶域で異なる型のデータが保持出きるので、それぞれの型の表現に必要な記憶域の最大のもおを取っておくことになる。

union val{
    int i_val;
    float f_val;
    char *s_val;
}v;

クラス

あるクラスを表現するものは、そのクラスに1つしかないものと、そのクラスの各インスタンスに1つずつあるものからなる。前者は、クラス変数、クラスメソッド、インスタンスメソッド、スーパークラスへのポインタ、クラス定数などで、後者はインスタンス変数である。

インスタンスメソッドについて

インスタンスメソッドは、各インスタンスが持っているかのように説明されることがあるが、実際には従来の手続きを、第一引数にインスタンスの情報をつけて呼び出すのと同じである。実際、C++Javaでもこのように実装されている。(ここら辺の仕組みについては次回やりたい)

以下のコードは、オブジェクトaにメッセージfと引数bを送ることであり、オブジェクトaがメソッドfを実行すると説明されることが多い。

a.f(b);

しかし、実際は、以下のような手続きをするのと同じ。

f(a, b);

PythonとかPerlをやってる人は、何当たり前の事言ってるんだ?って感じではないだろうか。

インスタンスを第一引数に指定する。習慣としてselfを書くことになっている。

class a:
    def f(self):
        ...
...

メソッドの場合、最初の引数を$selfに代入する

package a;
...
sub f{
    my $self = shift;
    ...
}

...
インスタンス

あるクラスのインスタンスは、図5,もしくは図6のように表現されている


図5




図6



図5の(b)はhandleと呼ばれている。ここで、インスタンスごとの表現はインスタンス変数として宣言されたものである。また、クラスに1つは、クラス変数、メソッド、スーパークラスへのポインタなどである。これは、JVMでは、Classという名前のクラスのオブジェクトとして表現されている。

継承(単一の場合)

単一継承の場合、サブクラスは、スーパークラスの表現の後ろにそのサブクラスで宣言されたものを付け加えた形になる。

class Point {
    float x;
    float y;
}

class ColoredPoint extends Point {
    int c;
}

上のような場合、そのインスタンスは以下のように表現される。


図7



また、メソッドは、以下のように、あるクラスで使えるメソッド(スーパークラスで定義されているものも含む)の情報をメソッドテーブルとして表現されたりする。

class A {
      int x;
      int y;
      void f(){ ... }
      void g(){ ... }
}

class B extends A {
      int c;
      void f(){ ... }
      void h(){ ... }
}


図8