이 페이지의 최신 내용은 아직 번역되지 않았습니다. 최신 내용은 영문으로 볼 수 있습니다.

효율적인 메모리 사용을 위한 전략

메모리 요구량을 줄이는 방법

"메모리 부족" 문제의 원인은 파일 또는 데이터베이스 내에 있는 기존 대규모 데이터 세트의 분석이나 처리와 관련이 있는 경우가 많습니다. 이런 데이터를 분석하거나 처리하려면 데이터 세트의 전체나 부분에 대한 MATLAB® 프로세스를 거쳐야 합니다. 다음 기법은 이 단계 동안 필요한 메모리를 최소화하는 일을 합니다.

필요한 양의 데이터만 불러오기

대규모 데이터 세트 중에서 해결하려는 문제에 필요한 만큼만 MATLAB으로 가져옵니다. 이는 일반적으로 데이터베이스 등의 소스에서 가져올 때는 쿼리와 일치하는 요소를 명시적으로 검색할 수 있으므로 문제가 되지 않습니다. 반면 대용량의 일반 텍스트나 이진 파일을 불러올 때 흔히 발생하는 문제입니다. 전체 파일을 불러오는 대신, 적절한 MATLAB 함수를 사용하여 파일의 일부만 불러오십시오.

파일 형식부분 불러오기
MAT 파일

matfile 함수를 사용하여 생성한 객체의 요소를 참조하여 변수의 일부를 불러옵니다.

텍스트 파일

textscan 함수를 사용하면 선택한 열과 행만 읽어 들여 대용량 텍스트 파일의 일부에 액세스할 수 있습니다. textscan을 사용하여 행 개수나 반복 형식 번호를 지정하는 경우, MATLAB은 정확히 필요한 메모리 양을 사전에 계산합니다.

이진 파일

fread와 같은 로우 레벨 이진 파일 I/O 함수를 사용하면 알려진 형식의 파일 일부에 액세스할 수 있습니다. 알 수 없는 형식의 이진 파일의 경우에는 memmapfile 함수를 사용하여 메모리 매핑을 시도해 보십시오.

이미지, HDF, 오디오, 비디오 파일

이러한 유형의 파일에서 불러올 수 있도록 지원하는 다수의 MATLAB 함수는 읽을 데이터의 일부를 선택할 수 있게 해 줍니다. 자세한 내용은 가져오기와 내보내기에 지원되는 파일 형식에 나열된 함수 도움말 페이지를 참조하십시오.

블록 단위로 데이터 처리하기

블록 처리, 즉 루프에서 대규모 데이터 세트를 한 번에 한 섹션씩 처리하는 방법을 고려해 보십시오. 데이터 세트에 있는 가장 큰 배열의 크기를 줄이면 필요한 복사본이나 임시 배열의 크기가 줄어듭니다. 이 기법은 다음 두 가지 경우에 사용할 수 있습니다.

  • 개별 청크로 분할하여 독립적으로 처리할 수 있는 일부 응용 프로그램의 경우

  • 필터링과 같이 이전 블록의 상태에만 의존하는 응용 프로그램의 경우

임시 배열 생성 지양하기

대용량 임시 변수를 만들지 말고, 임시 변수가 더 이상 필요하지 않을 때는 항상 이 변수를 지우는 것이 좋습니다. 예를 들어, 0으로 구성된 대형 배열을 만들 경우 다음과 같이 임시 변수 A에 저장한 후 A를 single형으로 변환하지 마십시오.

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

다음과 같이 하나의 명령만 사용하여 두 작업을 모두 수행하십시오.

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

repmat 함수를 사용하는 경우, 배열 사전할당(Preallocation)과 for 루프를 통해 메모리의 임시 저장 공간 없이도 nondouble형 데이터에 대한 작업을 수행할 수 있습니다.

중첩 함수를 사용하여 전달할 인수 개수 줄이기

대규모 데이터 세트를 가지고 작업할 때, 호출된 함수가 입력 변수의 값을 수정하는 경우 MATLAB이 이 입력 변수의 임시 복사본을 만든다는 것에 주의하십시오. 이때 배열을 저장하는 데 필요한 메모리가 일시적으로 배로 늘어나며, 이로 인해 충분한 메모리를 사용할 수 없는 경우 MATLAB에서 오류가 발생합니다.

이 상황에서 메모리 사용량을 줄이는 방법은 중첩 함수를 사용하는 것입니다. 중첩 함수는 모든 바깥쪽 함수의 작업 공간을 공유하여, 중첩 함수가 일상 범위 밖에 있는 데이터에 액세스할 수 있게 됩니다. 여기에 나온 예제에서는 중첩 함수 setrowval이 바깥쪽 함수 myfun의 작업 공간에 직접 액세스할 수 있어, 함수 호출에서 변수의 복사본을 전달할 필요가 없습니다. setrowvalA의 값을 수정하면 호출하는 함수의 작업 공간에서 이 값이 수정됩니다. 호출되는 함수에 대한 별도의 배열을 수용하기 위해 추가 메모리를 사용할 필요가 없으며, 수정된 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

적절한 데이터 저장소 사용하기

MATLAB에서는 double형, uint8형 등, 다양한 크기의 데이터 클래스를 제공합니다. 따라서 비교적 작은 데이터 세그먼트를 저장하는 데 크기가 큰 클래스를 사용할 필요가 없습니다. 예를 들어, 부호 없는 작은 정수 값 1,000개를 저장할 때 uint8형 클래스를 사용하면 double형 클래스를 사용할 때에 비해 7KB 더 적은 메모리를 차지합니다.

적절한 숫자형 클래스 사용하기

MATLAB에서 사용해야 할 숫자형 클래스는 의도하는 동작에 따라 달라집니다. 디폴트 double형 클래스를 사용하면 정밀도가 가장 높지만 요소당 8바이트의 메모리가 필요합니다. 선형 대수와 같은 복잡한 수학 연산을 수행하려는 경우 double형이나 single형과 같은 부동소수점 클래스를 사용해야 합니다. single형 클래스에는 4바이트만 필요합니다. single형 클래스로 수행할 수 있는 연산에는 몇 가지 제한 사항이 있지만, 대부분의 MATLAB 수학 연산이 지원됩니다.

단순 산술만 수행해야 하며 원래 데이터를 정수로 나타내는 경우 MATLAB의 정수형 클래스를 사용할 수 있습니다. 다음은 숫자형 클래스, 메모리 요구 사항(단위: 바이트), 지원되는 연산의 목록입니다.

클래스(데이터형)바이트지원되는 연산
single4대부분의 수학 연산
double8모든 수학 연산
logical1논리/조건 연산
int8, uint81산술 연산과 일부 간단한 함수
int16, uint162산술 연산과 일부 간단한 함수
int32, uint324산술 연산과 일부 간단한 함수
int64, int648산술 연산과 일부 간단한 함수

데이터 저장 시 오버헤드 줄이기

MATLAB 배열(내부적으로 mxArrays로 구현됨)은 유형, 차원, 특성(Attribute)과 같은 데이터에 대한 메타 정보를 저장할 공간이 메모리에 필요합니다. 배열당 약 80바이트가 사용됩니다. 이 오버헤드는 작은 mxArrays(예: 스칼라)가 대량(예: 수백 개 또는 수천 개)으로 있는 경우에만 문제가 됩니다. whos 명령은 변수가 사용하는 메모리를 나열하지만 이 오버헤드는 포함하지 않습니다.

하나의 mxArray로 구성된 간단한 숫자형 배열의 경우 오버헤드가 가장 적기 때문에, 가능한 경우 항상 이 배열을 사용해야 합니다. 데이터가 복잡해서 단순 배열(또는 행렬)에 저장할 수 없을 때는 다른 데이터 구조를 사용할 수 있습니다.

셀형 배열은 각 요소에 대한 별도의 mxArrays로 구성됩니다. 따라서 작은 요소 여러 개가 있는 셀형 배열의 경우 오버헤드가 커집니다.

구조체에는 필드당 비슷한 양의 오버헤드가 필요합니다(배열 헤더 항목 참조). 필드가 많으면서 그 내용이 작은 구조체는 큰 오버헤드를 가지므로 피해야 합니다. 숫자형 스칼라 필드가 있는 큰 구조체 배열은 큰 숫자형 배열이 포함된 필드를 가진 구조체보다 훨씬 더 많은 메모리를 필요로 합니다.

참고로, 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

가능한 경우 희소 배열 만들기

데이터에 0이 많이 포함된 경우 0이 아닌 요소만 저장하는 희소 배열을 사용하는 것이 좋습니다. 다음 예제에서는 주로 0으로 구성된 배열의 저장소에 필요한 공간을 비교합니다.

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  

이 배열을 희소 배열로 저장하려면 4KB만 있으면 되지만 비희소 행렬(Full Matrix)로 저장하려면 약 8MB가 필요한 것을 확인할 수 있습니다. 일반적으로, nnz(0이 아님) 요소와 ncol 열이 있는 double형 희소 배열의 경우 필요한 메모리는 다음과 같습니다.

  • 16 * nnz + 8 * ncol + 8바이트(64비트 컴퓨터의 경우)

  • 12 * nnz + 4 * ncol + 4바이트(32비트 컴퓨터의 경우)

참고로, MATLAB은 희소 배열에 대한 모든 수학 연산을 지원하지는 않습니다.

메모리 조각화를 방지하는 방법

MATLAB은 항상 연속 메모리 세그먼트를 사용해 숫자형 배열을 저장합니다. 그러나 이 데이터를 조작하는 과정에서 연속 블록이 조각화될 수 있습니다. 메모리가 조각화되면 여유 공간이 많이 있더라도 새로운 큰 변수를 저장할 연속 메모리는 부족할 수 있습니다. 조각화가 된 부분이 많아지면 필요 이상으로 현저히 더 많은 메모리를 사용할 수 있습니다.

배열 생성 시 연속 메모리 사전할당(Preallocation)하기

MATLAB 세션 중에 동적 메모리 할당 및 해제로 인해 메모리가 조각화될 수 있습니다. 루프를 돌 때마다 데이터 구조의 크기를 점차적으로 늘리거나 키우는 forwhile 루프는 데이터를 저장할 큰 메모리 블록을 반복적으로 찾아서 할당해야 하므로 조각화를 촉진시킬 수 있습니다.

메모리를 더 효율적으로 활용하려면, 루프 진입 전에 최종 크기의 행렬을 저장할 수 있을 정도로 충분히 큰 메모리 블록을 사전할당(Preallocation)해야 합니다. 배열에 대한 메모리를 사전할당하면 MATLAB은 계산을 시작할 때 전체 크기 배열을 충분히 수용할 수 있는 연속 공간을 예약합니다. 이 공간이 있으면 메모리에서 새 공간을 지속적으로 할당하지 않고도 요소를 배열에 추가할 수 있습니다

사전할당에 대한 자세한 내용은 사전할당(Preallocation) 항목을 참조하십시오.

큰 배열 우선 할당하기

MATLAB은 메모리를 관리하는 데 힙 방식을 사용합니다. 힙에 현재 변수를 저장할 수 있는 메모리가 충분하지 않은 경우 운영 체제로부터 메모리를 요청합니다. 그리고 필요한 메모리 세그먼트의 크기를 힙에서 사용할 수 있는 한 메모리를 재사용합니다.

다음 명령문에는 약 4.3MB의 RAM이 필요할 수 있습니다. 이는 MATLAB이 2.3MB짜리 배열에 공간을 할당할 때 이전에 두 개의 1MB짜리 배열이 차지하고 있던 공간을 재사용하지 못할 수 있기 때문입니다.

a = rand(1e6,1);
b = rand(1e6,1);
clear
c = rand(2.3e6,1);

메모리 초과 할당을 방지하는 가장 간단한 방법은 가장 큰 벡터를 먼저 할당하는 것입니다. 다음 명령문에는 약 2.0MB의 RAM만 필요합니다.

c = rand(2.3e6,1);
clear
a = rand(1e6,1);
b = rand(1e6,1);

장기적인 사용(Windows 시스템에만 해당)

32비트 Microsoft® Windows®에서는 Windows 메모리 관리자가 특정 유형과 크기의 블록을 운영 체제에 반환하지 않기 때문에 MATLAB의 작업 공간은 시간이 지남에 따라 조각화될 수 있습니다. MATLAB 작업 공간을 지워도 이 문제는 해결되지 않습니다. 가장 큰 변수를 먼저 할당하여 문제를 최소화할 수 있습니다. 그러나, 이렇게 해도 MATLAB을 며칠이나 몇 주에 걸쳐 지속적으로 사용함에 따라 발생하는 작업 공간 조각화는 해결할 수 없습니다. 이 문제를 해결할 수 있는 유일한 방법은 작업을 저장하고 MATLAB을 다시 시작하는 것입니다.

모든 변수를 디스크에 저장했다가 다시 불러오는 pack 명령은 이 상황에는 도움이 되지 않습니다.

사용한 메모리 반환 받기

사용 가능한 메모리 양을 늘릴 수 있는 한 가지 간단한 방법은 더 이상 사용하지 않는 큰 배열을 지우는 것입니다.

주기적으로 대용량의 데이터를 디스크에 저장하기

프로그램이 아주 큰 용량의 데이터를 생성하는 경우 데이터를 주기적으로 디스크에 쓰는 것이 좋습니다. 데이터의 해당 부분을 저장한 후에는 clear 함수를 사용하여 메모리에서 변수를 제거하고 데이터 생성을 계속합니다.

메모리에서 더 이상 필요 없는 오래된 변수 지우기

매우 큰 대규모 데이터 세트를 반복적으로 또는 대화형 방식으로 작업할 때는 먼저 오래된 변수를 지워 새 변수를 위한 공간을 만들도록 하십시오. 그러지 않으면, MATLAB은 변수를 재정의(Override)하기 전에 같은 크기의 임시 저장 공간을 필요로 합니다. 예를 들면 다음과 같습니다.

a = rand(100e6,1) % 800 MB array b = rand(100e6,1) % New 800 MB array Error using rand Out of memory. Type HELP MEMORY for your options. clear a a = rand(100e6,1) % New 800 MB array