Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

メモリを効率的に使用するための対策

このトピックでは、MATLAB® でメモリを効率的に使用するためのいくつかの手法を説明します。

適切なデータ ストレージの使用

MATLAB では、doubleuint8 などの、異なるサイズのデータ クラスが提供されています。このため、小さなデータ セグメントを格納するために大きなクラスを使用する必要はありません。たとえば、1,000 個の小さな符号なし整数値を格納するには、uint8 クラスを使用すれば、double クラスの場合よりも必要なメモリが 7 KB 少なくて済みます。

適切な数値クラスの使用

MATLAB では、操作の内容の応じて異なる数値クラスを使用できます。既定のクラス double では精度が最良となりますが、格納にはメモリの要素ごとに 8 バイトが必要です。線形代数のように複雑な計算を行う場合は、doublesingle などの浮動小数点クラスを使用しなければなりません。single クラスで必要なのは、4 バイトのみです。single クラスで実行できる操作にはいくつかの制約がありますが、ほとんどの MATLAB 数学演算がサポートされています。

簡単な演算のみを実行し、元のデータを整数として表す場合は、MATLAB の整数クラスを使用できます。以下に、数値クラス、必要なメモリ (バイト単位)、サポートされる演算を一覧にします。

クラス (データ型)バイトサポートされている演算
single4ほとんどの数学演算
double8すべての数学演算
logical1論理演算と条件付き演算
int8, uint81算術関数と一部の単純な関数
int16, uint162算術関数と一部の単純な関数
int32, uint324算術関数と一部の単純な関数
int64, int648算術関数と一部の単純な関数

データを格納する際のオーバーヘッドの削減

mxArrays として内部実装される MATLAB 配列では、タイプ、次元、属性など、データに関するメタ情報を保存するメモリ スペースが必要です。これには、配列ごとに約 104 バイト必要です。このオーバーヘッドは、多数の (何百または何千の) 小さな mxArrays (スカラー) がある場合には問題になります。whos コマンドでは変数で使用されるメモリが一覧表示されますが、このオーバーヘッドは含まれません。

1 つの mxArray で構成される簡単な数値配列ではオーバーヘッドが最小になるので、できるだけこの数値配列を使用するようにします。データが複雑すぎて単純な配列や行列に保存できない場合は、他のデータ構造を使用できます。

cell 配列は、各要素に対する別々の mxArrays で構成されます。このため、多くの小さな要素をもつ cell 配列ではオーバーヘッドが大きくなります。

構造体では、フィールドごとにほぼ同量のオーバーヘッドが必要です (配列ヘッダーを参照してください)。多くのフィールドと小さなコンテンツをもつ構造体は、オーバーヘッドが大きくなるので避けるようにします。数値スカラー フィールドをもつ構造体の大規模な配列では、大規模な数値配列を含むフィールドをもつ構造体よりも、多くのメモリが必要です。

また、MATLAB では数値配列が連続したメモリに格納されますが、構造体や cell 配列ではメモリは連続していないことに注意してください。

適切な MATLAB クラスへのデータのインポート

fread を使用してバイナリ ファイルからデータを読み込む場合、ファイル内のデータのクラスのみを指定し、データがワークスペースに読み込まれた後に MATLAB で使用されるデータ クラスを忘れてしまうというミスを犯しがちです。このような場合、わずか 8 ビットの値を読み取るとしても、既定の double が使用されます。たとえば、

fid = fopen('large_file_of_uint8s.bin', 'r'); 
a = fread(fid, 1e3, 'uint8');              % Requires 8k 
whos a
  Name         Size            Bytes  Class    Attributes
 
  a         1000x1              8000  double    
  
a = fread(fid, 1e3, 'uint8=>uint8');       % Requires 1k 
whos a
  Name         Size            Bytes  Class    Attributes
 
  a         1000x1              1000  uint8

可能であれば配列をスパースにする

データに多くのゼロが含まれる場合は、ゼロ以外の要素のみを格納する、スパース配列の使用を考慮します。次の例は、スパース ストレージと非スパース ストレージの要件を比較しています。

A = eye(1000);        % Full matrix with ones on the diagonal
As = sparse(A);       % Sparse matrix with only nonzero elements
whos
  Name         Size                Bytes  Class     Attributes

  A         1000x1000            8000000  double              
  As        1000x1000              24008  double    sparse  

この配列は、スパースとして保存すると約 4 KB しか必要としませんが、非スパース行列ではおよそ 8 MB が必要になることがわかります。一般に、非ゼロ要素が nnz 個、列数が ncol の double 型スパース配列で必要なメモリは以下のとおりです。

  • 16 * nnz + 8 * ncol + 8 バイト (64 ビットのコンピューターの場合)

MATLAB では、ほとんどの数学演算がスパース配列でサポートされていますが、全部ではありません。

データの一時コピーの回避

データの不必要な一時コピーの作成を回避することで、必要なメモリ量を大きく削減できます。

一時的な配列の作成の回避

大きな一時変数の作成を回避し、一時変数が不必要になった際にはクリアするようにします。たとえば、次のコードは一時変数 A として保存される、0 で構成された配列を作成した後、A を単精度に変換します。

A = zeros(1e6,1);
As = single(A);

1 つのコマンドを使用して両方の演算を実行する方が、メモリ効率は高くなります。

A = zeros(1e6,1,'single');

関数 repmat、配列の事前割り当て、および for ループや他の方法を使用しても、メモリ内で一時的なストレージを必要とせずに double でないデータを扱うことができます。

入力引数を減らすための入れ子関数の使用

大きなデータ セットを扱う場合には、呼び出された関数で値を変更する際に、MATLAB によって入力変数の一時的なコピーが作成されることに注意しなければなりません。このため、配列の格納に必要なメモリが 2 倍になり、十分なメモリがないと MATLAB でエラーが発生します。

このような状況で使用メモリを減らす方法の 1 つとして、入れ子関数を使用することが考えられます。入れ子関数は外側の関数すべてとワークスペースを共有するため、通常のスコープ外にあるデータにもアクセスできます。ここで示す例では、入れ子関数 setrowval は、外側の関数 myfun のワークスペースに直接アクセスでき、関数呼び出しにおいて変数のコピーを渡す必要はありません。setrowval によって A の値が変更される際には、呼び出し側の関数のワークスペース内で変更されます。呼び出す関数のために個別の配列を保持するための追加メモリは必要なくA の変更された値を返す必要もありません。

function myfun
A = magic(500);

   function setrowval(row, value)
   A(row,:) = value;
   end

setrowval(400, 0);
disp('The new value of A(399:401,1:10) is')
A(399:401,1:10)
end

使用されたメモリの再利用

使用可能なメモリの量を簡単に増やす方法の 1 つとして、使用していない大きな配列をクリアすることがあげられます。

大きなデータの定期的なディスクへの保存

プログラムで大量のデータが生成される場合、データを定期的にディスクに書き込むようにします。この部分のデータを保存した後に、メモリから変数を clear して、データ生成を続行します。

不要な変数のメモリからのクリア

非常に大規模なデータ セットを繰り返し、または対話形式で扱う場は合、まず古い変数をクリアして、新しい変数のための容量を確保します。この作業を行わない場合、変数をオーバーライドにする前に、MATLAB で同じサイズの一時的なストレージが必要になります。以下に例を示します。

a = rand(1e5);
b = rand(1e5);
Out of memory.

More information
 
 
clear a
a = rand(1e5);              % New array 

関連するトピック