Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

高效使用内存的策略

本主题介绍在 MATLAB® 中高效使用内存的几种方法。

使用适当的数据存储

MATLAB 提供了不同大小的数据类(例如 doubleuint8),因此您无需使用大型类存储较小的数据段。例如,与使用 double 相比,使用 uint8 类存储 1,000 个无符号小整数值所用的内存少 7 KB。

使用相应的数值类

您应在 MATLAB 中使用的数值类取决于您的预期操作。默认类 double 可提供最佳精度,但存储每个元素需要 8 字节内存。如果您计划执行复杂的数学运算(例如线性代数),则您必须使用浮点类,例如 doublesinglesingle 类只需要 4 个字节。可使用 single 类执行的操作存在某些限制,但多数 MATLAB 数学运算都受支持。

如果您只需执行简单的算术运算并将原始数据表示为整数,则您可以在 MATLAB 中使用整数类。下面是数值类、内存要求(以字节为单位)及支持的运算的列表。

类(数据类型)字节支持的运算
single4绝大多数的数学运算
double8所有数学运算
logical1逻辑/条件运算
int8, uint81算术和某些简单函数
int16, uint162算术和某些简单函数
int32, uint324算术和某些简单函数
int64, uint648算术和某些简单函数

减少存储数据时的开销量

MATLAB 数组(在内部作为 mxArrays 实现)需要一定的空间来将有关数据的元数据信息(例如类型、维度和属性)存储在内存中。每个数组大约需要 104 字节。仅当有大量(如数百或数千)较小的 mxArrays(如标量)时,此开销才成问题。whos 命令列出了变量所用的内存,但不包括此开销。

因为简单数值数组(包括一个 mxArray)的开销最少,所以您应该尽可能使用它们。当数据太复杂而无法存储在简单数组(或矩阵)中时,您可以使用其他数据结构体。

元胞数组由每个元素的单独 mxArrays 组成。因此,包含许多小元素的元胞数组具有较大的开销。

结构体的每个字段需要类似的开销量。包含许多字段和较少内容的结构体具有较大的开销,因此应避免使用这样的结构体。由包含数值标量字段的结构体组成的大型数组所需的内存要比具有包含较大数值数组的字段的结构体更多。

另请注意,虽然 MATLAB 将数值数组存储在连续内存中,但结构体和元胞数组则不然。有关详细信息,请参阅MATLAB 如何分配内存

将数据导入相应的 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  

您可以看到,该数组只需要大约 24 KB 即可存储为稀疏数组,但要存储为满矩阵,则需要大约 8 MB。通常,对于包含 nnz 非零元素和 ncol 列的双精度型稀疏数组,所需的内存为:

  • 16 * nnz + 8 * ncol + 8 字节(在 64 位计算机上)

请注意,MATLAB 支持对稀疏数组执行大多数(但不是全部)数学运算。

避免临时性的数据副本

避免创建不必要的临时性数据副本,以显著减少所需的内存量。

避免创建临时数组

避免创建大型临时变量,并在不再需要这些临时变量时清除它们。例如,以下代码创建由零组成的、存储为临时变量 A 的数组,然后将 A 转换为单精度:

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

使用一个命令来执行两个操作可更高效地使用内存:

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

使用 repmat 函数、数组预分配和 for 循环是处理非双精度数据而不需要内存中的临时存储的其他方法。

使用嵌套函数减少传递的参数

处理大型数据集时,注意 MATLAB 会创建输入变量的临时副本(如果被调用函数修改其值)。这会暂时使存储数组所需的内存翻倍,从而导致 MATLAB 在没有足够内存时生成错误。

在此情形下使用较少的内存的一种方法是使用嵌套函数。嵌套函数共享所有外部函数的工作区,为嵌套函数提供对其通常范围之外的数据的访问权。在如下示例中,嵌套函数 setrowval 可直接访问外部函数 myfun 的工作区,从而无需在函数调用中传递变量副本。当 setrowval 修改 A 的值时,它在调用函数的工作区中修改它。无需使用额外内存为所调用函数存储一个单独数组,且无需返回 A 的修改后的值:

function myfun
A = magic(500);
setrowval(400,0)
disp('The new value of A(399:401,1:10) is')
A(399:401,1:10)

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

回收使用的内存

增加可用内存量的一种简单方法是清除您不再使用的大型数组。

定期将您的大型数据保存到磁盘

如果您的程序生成非常大量的数据,请考虑定期将数据写入磁盘。在保存该部分数据后,使用 clear 函数从内存中删除变量并继续生成数据。

从内存中清除不再需要的旧变量

当您重复或以交互方式处理非常大的数据集时,请首先清除旧变量以为新变量腾出空间。否则,MATLAB 需要等大小的临时存储才能覆盖此变量。例如,

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

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

相关主题