ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

MATLAB でのメモリの割り当て方法

配列へのメモリの割り当て

次のトピックでは、配列および変数を扱う際に、MATLAB® でメモリを割り当てる方法について述べます。コードを記述する際に、メモリのより効率な使用を支援することを目的としています。ただしほとんどの場合、MATLAB ではデータ ストレージが自動的に処理されるので、これらの内部処理について心配することはありません。

    メモ:   MATLAB によるデータの内部的な処理に関する情報は、将来のリリースで変更されることがあります。

配列の作成と編集

数値配列や文字配列を変数に代入する場合、MATLAB では、メモリの連続したバーチャル ブロックを割り当て、そのブロックに配列データを保存します。また、MATLAB では、クラスや次元などの配列データに関する情報も "ヘッダー" と呼ばれる別の小さなメモリ ブロックに保存されます。

既存の配列に新しい要素を追加すると、メモリ内のストレージを連続に保つように、MATLAB によって既存の配列が拡張されます。このため、通常、拡張した配列を保持するために十分な大きさの新しいメモリ ブロックを見つけなければなりません。MATLAB によって、配列のコンテンツが元の位置から新しいメモリ ブロックにコピーされ、ブロックの配列に新しい要素が追加され、メモリの元の配列の位置が解放されます。

既存の配列から要素を削除すると、MATLAB では、削除した要素が除去されてメモリ ストレージが連続に保たれ、元のメモリの位置でストレージが圧縮されます。

大きなデータ セットの扱い-  大きなデータ セットを扱う場合、メモリ不足が原因で起こるエラーを避けるために、配列のサイズを増やすときには注意が必要です。元の位置で使用可能な連続メモリを超えて配列を拡張する場合、MATLAB では、上に説明したように、メモリの新しい位置に配列のコピーが作成され、この配列に新しい値が設定されます。この処理の間は、メモリに元の配列のコピーが 2 つ存在するため、配列に必要なメモリ量が一時的に 2 倍になり、プログラムの実行中にメモリが不足する可能性が増加します。配列で考えられる最大サイズに対し、十分なメモリをあらかじめ割り当てておくことを推奨します。事前割り当てを参照してください。

配列のコピー

内部的には、複数の変数で同じデータ ブロックを指し、配列の値を共有することができます。変数を他の変数にコピーする (たとえば、B = A) 場合、MATLAB では、配列ではなく、配列参照のコピーが作成されます。配列のコンテンツを変更しない限り、複数のコピーを保存する必要はありません。配列の要素を変更する場合は、MATLAB によって配列のコピーが作成され、このコピーが変更されます。

次の例は、この処理方法を示しています。MATLAB プロセスで使用しているメモリ量を表示するために、まず簡単なスクリプト memUsed.m を作成します。以下の 2 行のコードをスクリプトに記述します。

[usr, sys] = memory;
usr.MemUsedMATLAB

MATLAB プロセスで使用されているメモリ量の初期値を取得します。

format short eng;
memUsed
ans =
   295.4977e+006

2000 行 2000 列の数値配列 A を作成します。これは、およそ 32 MB のメモリを使用します。

A = magic(2000);
memUsed
ans =
   327.6349e+006

B に配列 A のコピーを作成します。配列データのコピーが 2 つある必要はないので、MATLAB は配列参照のコピーのみを作成します。このため、メモリの使用量が大幅に増加することはありません。

B = A;
memUsed
ans =
   327.6349e+006

B を変更して、元のサイズの半分にします。つまり、1000 行分を空にします。この作業を行うには、MATLAB によって配列 A の少なくとも最初の 1000 行がコピーされ、このコピーが B に代入されます。

B(1001:2000,:) = [];
format short;   size(B)
ans =
        1000        2000

再び、使用されているメモリを確認します。B は元のサイズに比べて大幅に小さくなっていますが、BA への参照のみではなくなったため、MATLAB のプロセスで使用されるメモリ量は約 16 MB (元々 A に必要だった 32 MB の半分) 増加しました。

format short eng;   memUsed
ans =
   343.6421e+006

配列ヘッダー

変数に配列を代入すると、MATLAB ではヘッダーと呼ばれる別のメモリ断片に配列に関する情報 (クラスや次元など) が保存されます。ほとんどの配列では、ヘッダーを保存するために必要なメモリは大きくありません。大規模なデータ セットを、多数の小さな配列ではなく、少数の大きな配列に格納した場合は、必要なメモリがやや少なくなります。これは、前者では必要な配列ヘッダー数が少なく構成されているためです。

構造体とセル配列-  構造体とセル配列では、MATLAB では各配列に対してのみでなく、構造体の各フィールド、セル配列の各セルに対してもヘッダーが作成されます。このため、構造体またはセル配列を格納するために必要なメモリ量は、保存するデータ量だけでなく作成方法にも依存します。

たとえば、フィールド RGB をもつ、スカラー構造体配列 S1 を考えてみましょう。サイズが 100 x 50 の各フィールドでは、構造体全体を記述するための配列ヘッダーが 1 つ、一意に定まるフィールド名それぞれに対してヘッダーが 1 つずつ、1 行 1 列の構造体配列のフィールドごとにヘッダー 1 つが必要です。これにより、データ構造全体で合計 7 つの配列ヘッダーが作成されます。

S1.R(1:100,1:50)
S1.G(1:100,1:50)
S1.B(1:100,1:50)

一方、各要素がスカラー フィールド RGB である 100 行 50 列の構造体配列 S2 を考えてみましょう。この例では、構造体全体を記述するために配列ヘッダー 1 つ、各フィールド名に対してヘッダー 1 つずつ、構造体の 5,000 要素ごとにフィールドあたりヘッダー 1 つが必要で、データ構造全体で合計 15,004 の配列ヘッダーが作成されます。

S2(1:100,1:50).R
S2(1:100,1:50).G
S2(1:100,1:50).B

S1S2 は同じ量のデータを含みますが、S1 では使用するメモリがかなり少なくなります。S1 の形式を使用すると、必要なメモリが少なくて済むだけでなく、処理速度が速くなります。

データ構造とメモリの「セル配列」と「構造体」を参照してください。

関数 whos で表示されるメモリの使用状況-  関数 whos では、変数で消費されるメモリ量が表示されます。簡便さのために、whos では実際のデータの格納に使用するメモリのみが表示されます。たとえば、配列ヘッダーのストレージは含まれません。

関数の引数

MATLAB では、関数呼び出しで渡される引数が同様に扱われます。関数に 1 つの変数を渡すときには、実際は、変数が表すデータに対する参照も渡しています。呼び出された関数で入力データが変更されない限り、呼び出し側の関数内の変数と、呼び出された関数内の変数は、メモリ内の同じ位置を指しています。呼び出された関数で入力データの値が変更される場合は、MATLAB によってメモリ内の新しい位置に元の配列のコピーが作成され、このコピーが変更された値で更新され、呼び出された関数内の入力変数がこの新しい配列を指すようになります。

次の例では、関数 myfun によって渡された配列の値が変更されます。MATLAB によって、A が指す配列のコピーがメモリに作成され、変数 X がこの新しい配列への参照に設定され、X の 1 行がゼロに設定されます。A により参照される配列は、変更されません。

A = magic(500);
myfun(A);

function myfun(X)
X(400,:) = 0;

呼び出し側の関数で myfun に渡した配列の変更された値が必要な場合は、ここで変数 A に対して示すように、呼び出された関数の出力として更新された配列を返さなければなりません。

A = magic(500);
A = myfun(A);
sprintf('The new value of A is %d', A)

function Y = myfun(X)
X(400,:) = 0;
Y = X;

データ構造とメモリ

必要なメモリ量は、さまざまな MATLAB のデータ構造によって異なります。MATLAB での格納方法を工夫すると、これらの構造で使用するメモリ量を減らせる場合があります。

数値配列

MATLAB では、8 ビット、16 ビット、32 ビット、64 ビットの符号付きおよび符号なし整数を格納するために、それぞれ、1、2、4、8 バイトが必要です。浮動小数点数 single 型と double 型に対しては、それぞれ、4 または 8 バイトを使用します。数値配列を取り扱う際にメモリを節約するために、MathWorks® では、オーバーフローせずにデータを格納できる最小の整数型または浮動小数点型を使用することをお勧めします。詳細は、「数値型」を参照してください。

複素数配列

MATLAB では、複素数データが実数部と虚数部として別々に格納されます。複素配列変数のコピーを作成して、配列の実数部または虚数部のみを変更すると、MATLAB では実数部と虚数部の両方を含む配列が作成されます。

スパース行列

大部分がゼロ値である行列は、スパース形式に格納することを推奨します。非スパース行列と比べて、スパース行列が使用するメモリは少なく、操作が高速になります。関数 sparse を使用して、非スパース行列をスパース形式に変換できます。

2 つの 1000 行 1000 列の行列を比較します。X は要素の 3 分の 2 がゼロである double の行列、YX をスパース行列に変換したコピーです。次の例は、スパース行列では必要なメモリがほぼ半分になることを示しています。

whos
  Name      Size                   Bytes  Class

  X      1000x1000               8000000  double array
  Y      1000x1000               4004000  double array (sparse)

セル配列

セル配列では、データ ストレージに加え、各セルを説明する情報を格納するメモリがをある程度必要となります。この情報は "ヘッダー" に記録されます。配列の各セルに対して 1 つのヘッダーがあります。データを含まない 1 x 1 セルで消費されるバイト数がわかれば、セル配列ヘッダーに必要なメモリ量を判断することができます。次に 32 ビット システムの場合を示します。

A = {[]};      % Empty cell array

whos A
  Name      Size            Bytes  Class    Attributes

  A         1x1                60  cell

この場合、MATLAB によって、32 ビット システムではセル配列の各ヘッダーに 60 バイト必要であることが表示されます。これは、この節のすべての 32 ビットの例で使用されるヘッダー サイズです。64 ビット システムの場合、このドキュメンテーションではヘッダー サイズを 112 バイトと仮定しています。上に示した 32 ビットに対する方法を使用して、64 ビット システムでの正確なヘッダー サイズを求めることができます。

セル配列全体のサイズを予測するには、ここで求めたヘッダー サイズと配列内のセルの総数を乗算して、さらに配列に格納するデータに必要なバイト数を加えます。

(header_size x number_of_cells) + data

したがって、400 バイトのデータを含む 10 行 20 列のセル配列では、64 ビット システムで 22,800 バイトのメモリが必要です。

(112 x 200) + 400 = 22800

    メモ:   数値配列は連続したメモリに保存しなければなりませんが、構造体とセル配列ではその必要はありません。

例 1 - セル配列へのメモリの割り当て-  次の 4 行 1 列のセル配列では、3 つのノートブック コンピューターのブランド名、スクリーン サイズ、販売状況が記録されます。

Laptops = {['SuperrrFast 89X', 'ReliablePlus G5', ...
            'UCanA4dIt 140L6']; ...
           [single(17), single(15.4), single(14.1)]; ...
           [2499.99, 1199.99, 499.99]; ...
           [true, true, false]};

32 ビット システムでは、セル配列ヘッダーだけでセルあたり 60 バイトが必要です。

4 cells * 60 bytes per cell = 240 bytes for the cell array

4 つのセルそれぞれにデータを含むために必要なメモリを計算します。

45 characters * 2 bytes per char = 90 bytes
 3 doubles * 8 bytes per double = 24 bytes
 3 singles * 4 bytes per single = 12 bytes
 3 logicals * 1 byte per logical = 3 bytes

90 + 24 + 12 + 3 = 129 bytes for the data

2 つを加算して、結果を MATLAB から返されたサイズと比較します。

240 + 129 = 369 bytes total

whos Laptops
  Name         Size            Bytes  Class    Attributes

  Laptops      4x1               369  cell 

構造体

S.A = [];
B = whos('S');
B.bytes - 60
ans =
    64

以下のように、構造体配列に必要なメモリを計算します。

32-bit systems:  fields x ((60 x array elements) + 64) + data
64-bit systems:  fields x ((112 x array elements) + 64) + data

64 ビットのコンピューター システムでは、フィールド AddressPhone をもつ 4 行 5 列の構造体 Clients は、構造体のみで 4,608 バイトを使用します。

2 fields x ((112 x 20) + 64) = 2 x (2240 + 64) = 4608 bytes

この値に対し、各フィールドに代入されるデータの保持に必要なメモリを追加しなければなりません。4 行 5 列の配列 Clients の各要素において、Address に 25 文字ベクトル、Phone に 12 文字ベクトルを代入すると、データでは 1480 バイトが使用されます。

(25+12) characters * 2 bytes per char * 20 elements = 1480 bytes

2 つを加算すると、構造体全体では 6,088 バイトのメモリを消費することがわかります。

例 1 - 構造体配列へのメモリの割り当て-  32 ビット システム上にある、以下の 4 つのフィールドをもつ 6 行 5 列の構造体配列を格納するために必要なメモリ量を計算します。

A:  5-by-8-by-6 signed 8-bit integer array
B:  1-by-500 single array
C:  30-by-30 unsigned 16-bit integer array
D:  1-by-27 character array

配列の作成:

A = int8(ones(5,8,6));
B = single(1:500);
C = uint16(magic(30));
D = 'Company Name: MathWorks';

s = struct('f1', A, 'f2', B, 'f3', C, 'f4', D);

for m=1:6
   for n=1:5
      s(m,n)=s(1,1);
   end
end

まず構造体自体に必要なメモリ量を計算し、次に構造体が含むデータに必要なメモリ量を計算します。

structure = fields x ((60 x array elements) + 64) =
            4 x ((60 x 30) + 64) = 7,456 bytes

data = (field1 + field2 + field3 + field4) x array elements =
       (240 + 2000 + 1800 + 54) x 30 = 122,820 bytes

2 つを加算して、結果を MATLAB から返されたサイズと比較します。

Total bytes calculated for structure s: 7,456 + 122,820 = 130,276

whos s
  Name      Size            Bytes  Class     Attributes

  s         6x5             130036  struct
この情報は役に立ちましたか?