불필요한 데이터 복사본 방지하기
함수에 값 전달하기
입력 인수와 함께 함수를 호출할 경우 MATLAB®은 호출하는 함수의 작업 공간에서 호출되는 함수의 파라미터 변수로 값을 복사합니다. 하지만 MATLAB은 필요하지 않은 경우 이러한 값의 복사본을 생성하지 않도록 여러 기법을 적용합니다.
MATLAB은, C++ 같은 언어와 달리, 값에 대한 참조를 정의하는 방법을 제공하지 않습니다. 대신 MATLAB은 출력값과 입력 파라미터를 여러 개 사용하도록 허용하기 때문에 어떤 값이 함수에 입력으로 들어가고 어떤 값이 함수에서 출력으로 나오는지 알 수 있습니다.
쓰기 시 복사(copy-on-write)
함수가 입력 인수를 수정하지 않는 경우 MATLAB은 입력 변수에 포함된 값의 복사본을 생성하지 않습니다.
예를 들어, 큰 배열을 함수에 전달한다고 가정하겠습니다.
A = rand(1e7,1); B = f1(A);
함수 f1
은 입력 배열 X
에 포함된 각 요소에 1.1
을 곱한 후 그 결과를 변수 Y
에 할당합니다.
function Y = f1(X) Y = X.*1.1; % X is a shared copy of A end
함수가 입력값을 수정하지 않기 때문에 지역 변수 X
와 호출자 작업 공간에 있는 변수 A
가 데이터를 공유합니다. f1
이 실행된 후, A
에 할당된 값은 변경되지 않습니다. 호출자 작업 공간의 변수 B
는 요소별 곱셈의 결과를 포함합니다. 입력값이 값으로 전달됩니다. 그러나 f1
을 호출할 때 복사본이 생성되지 않습니다.
함수 f2
는 입력 변수의 로컬 복사본을 수정하므로 로컬 복사본이 입력값 A
와 공유되지 않습니다. 함수에서 X
의 값이 이제 호출자 작업 공간에서는 입력 변수 A
의 독립적인 복사본이 됩니다. f2
가 호출자 작업 공간에 결과를 반환하면 지역 변수 X
가 제거됩니다.
A = rand(1e7,1); B = f2(A);
function Y = f2(X) X = X.*1.1; % X is an independent copy of A Y = X; % Y is a shared copy of X end
입력값을 MATLAB 표현식으로 전달하기
함수에서 반환된 값을 다른 함수에 대한 입력 인수로 사용할 수 있습니다. 예를 들어, rand
함수를 사용하여 함수 f2
의 입력값을 직접 생성할 수 있습니다.
B = f2(rand(1e7,1));
rand
에서 반환된 값을 유지하는 변수만 함수 f2
의 작업 공간에서 임시 변수 X
가 됩니다. 호출자 작업 공간에는 공유되는 값이나 값에 대한 독립적인 복사본이 없습니다. 함수 출력값을 직접 전달하면 호출되는 함수의 입력값에 대한 복사본을 생성하는 데 필요한 시간과 메모리가 절약됩니다. 이 방법은 입력값이 다시 사용되지 않는 경우에 적합합니다.
같은 위치에(In-place) 할당하기
최초 입력값을 유지할 필요가 없는 경우 그 입력값의 원래 변수에 함수의 출력값을 할당할 수 있습니다.
A = f2(A);
같은 위치에 할당하는 경우 앞서 설명한 쓰기 시 복사(copy-on-write) 동작을 따릅니다. 입력 변수 값을 수정하면 해당 값의 임시 복사본이 생성됩니다.
특정 조건에서는 MATLAB이 메모리 최적화를 적용할 수 있습니다. 다음 예제를 살펴보겠습니다. canBeOptimized
함수는 변수 A
에 난수로 구성된 큰 배열을 생성합니다. 그런 다음, 로컬 함수 fLocal
을 호출하여 A
를 입력값으로 전달하고 로컬 함수의 출력값을 동일한 변수 이름에 할당합니다.
function canBeOptimized A = rand(1e7,1); A = fLocal(A); end function X = fLocal(X) X = X.*1.1; end
로컬 함수에 대한 호출 A = fLocal(A)
가 출력값을 변수 A
에 할당하기 때문에 MATLAB은 함수가 실행되는 동안 A
의 원래 값을 유지할 필요가 없습니다. fLocal
내에서 X
에 수정이 생기더라도 데이터 복사본이 생성되지 않습니다. 대입식 X = X.*1.1
은 같은 위치에서 X
를 수정하며 곱셈의 결과를 받을 배열을 새로 할당하지 않습니다. 로컬 함수에서 복사본을 제거하면 메모리가 절약되고 큰 배열의 실행 속도가 향상됩니다.
하지만 MATLAB은 로컬 함수에서 일어나는 할당에 배열 인덱싱이 필요한 경우 이 최적화를 적용할 수 없습니다. 예를 들어, updateCells
에서 생성된 셀형 배열을 수정하려면 로컬 함수 gLocal
에서 X
로 인덱싱해야 합니다. 매 루프 반복 i
에 대해 X{i} = X{i}*1.1
형식의 루프로 구성된 할당은 X{i}*1.1
의 값을 평가하고 저장하기 위해 X{i}
와 크기가 동일한 임시 변수를 생성합니다. MATLAB은 X{i}
에 값을 할당한 후 임시 변수를 제거합니다.
function updateCells C = num2cell(rand(1e7,1)); C = gLocal(C); end function X = gLocal(X) for i = 1:length(X) X{i} = X{i}*1.1; end end
여러 제한 사항이 추가로 적용됩니다. 함수가 오류를 발생시킨 후에 해당 변수가 사용될 가능성이 있으면 MATLAB은 메모리 최적화를 적용할 수 없습니다. 따라서, 이러한 최적화는 스크립트, 명령줄, eval
에 대한 호출 또는 try/catch
블록 내 코드에 적용되지 않습니다. 또한, MATLAB은 호출된 함수를 실행하는 도중 원래 변수에 직접 액세스가 가능한 경우에도 메모리 최적화를 적용하지 않습니다. 예를 들어, fLocal
이 중첩 함수이면 부모 함수와 변수를 공유할 수 있으므로 MATLAB이 최적화를 적용할 수 없습니다. 마지막으로, MATLAB은 할당된 변수가 전역(Global) 변수이거나 영속(Persistent) 변수로 선언된 경우 메모리 최적화를 적용하지 않습니다.
같은 위치 할당을 사용하는 코드 디버그하기
MATLAB이 대입문에 인 플레이스 최적화(In-place Optimization)를 적용할 때, 대입문의 좌변에 있는 변수는 임시 상태로 설정되어 MATLAB이 대입문의 우변을 실행하기 전에 액세스할 수 없습니다. 대입문 우변의 실행 결과가 변수에 할당되기 전에 MATLAB이 디버거에서 멈춰 있는 경우, 좌변 변수를 검토하면 변수를 사용할 수 없음을 나타내는 오류가 발생할 수 있습니다.
예를 들어, 이 함수에는 변수 A
와 B
의 차원에 불일치가 있습니다.
function A = inPlace A = rand(100); B = rand(99); dbstop if error A = A.*B; end
함수를 실행하면 오류가 발생하고 디버거에서 실행이 멈춥니다.
inPlace
Matrix dimensions must agree. Error in inPlace (line 5) A = A.*B; 5 A = A.*B;
디버그 모드에 있는 동안 변수 A
의 값을 확인하려고 하면 변수를 일시적으로 사용할 수 없기 때문에 오류가 발생합니다.
K>> A
Variable "A" is inaccessible. When a variable appears on both sides of an assignment statement, the variable may become temporarily unavailable during processing.
디버그할 때 유연성을 향상시키려면 코드를 리팩터링하여 같은 위치 할당을 제거하십시오. 예를 들어, 결과를 다른 변수에 할당해 보겠습니다.
function A = inPlace A = rand(100); B = rand(99); dbstop if error % Assign result to C instead of A C = A.*B; A = C; end
그러면 디버거에 있는 동안 변수 A를 볼 수 있습니다.
값 방식 전달(pass-by-value) 의미 체계를 사용하는 이유
함수로 인수를 전달하고 함수에서 값을 반환할 때 MATLAB은 값 방식 전달 의미 체계를 사용합니다. 어떤 경우에는 값 방식 전달을 사용하면 호출된 함수에서 원래 값의 복사본에 생성됩니다. 그러나 값 방식 전달 의미 체계는 몇 가지 이점이 있습니다.
함수를 호출할 때 호출자 작업 공간에서 입력 변수가 수정되지 않는다는 것을 알 수 있습니다. 따라서, 단지 값이 수정될 가능성에 대비하기 위해 함수 내에서 또는 호출하는 위치에서 입력값의 복사본을 생성할 필요가 없습니다. 반환된 값에 할당된 변수만 수정됩니다.
또한, 참조 방식으로 변수가 전달된 함수 내에서 오류가 발생할 경우 작업 공간 변수가 손상될 가능성을 없앨 수 있습니다.
핸들 객체
핸들이라고 하는 특수한 종류의 객체가 있습니다. 동일한 핸들의 복사본을 유지하는 모든 변수는 동일한 기본 객체를 액세스하고 수정할 수 있습니다. 핸들 객체는 객체가 숫자 또는 행렬과 같은 수학 객체가 아닌 창, 플롯, 장치 또는 사람과 같은 실제 객체를 나타내는 특수한 경우에 유용합니다.
핸들 객체는 이벤트 및 리스너, 소멸자 메서드, 동적 속성 지원과 같은 기능을 제공하는 handle
클래스에서 파생됩니다.
값과 핸들에 대한 자세한 내용은 핸들 클래스와 값 클래스 비교 항목과 Which Kind of Class to Use 항목을 참조하십시오.