스택 프레임
메소드가 호출되면 스택(Stack) 영역에는 해당 메소드만을 위한 독립적인 공간인 스택 프레임이 생성된다.
-
구성 요소: 메소드로 전달된 매개 변수, 메소드 내의 지역 변수 그리고 작업이 끝난 후 돌아갈 복귀 주소(Return Address)가 포함된다.
-
생명 주기: 메소드가 실행을 시작할 때 스택에 쌓이고 종료되는 순간 즉시 제거된다.
-
심층 분석: 스택 프레임 덕분에 재귀 호출이 가능해지며, 각 호출은 서로 독립적인 지역 변수 공간을 가진다. 하지만 깊은 호출은 StackOverflowException 예외를 유발한다.
파라미터 전달 방식
C# 언어는 데이터의 복사 비용을 줄이고 의도를 명확히 하기 위해 다양한 키워드를 제공한다.
| 키워드 | 이름 | 특징 및 내부 동작 |
|---|---|---|
| 기본(Value) | 값 전달 | 데이터를 복사하여 전달한다. 원본 변수에는 영향을 주지 않는다. |
| ref | 참조 전달 | 변수의 메모리 주소를 전달한다. 메소드 내부의 수정이 원본에 즉시 반영된다. |
| out | 출력 전용 참조 | ref와 같으나, 메소드를 나갈 때 반드시 값을 할당해야 함을 컴파일러가 강제한다. |
| in | 입력 전용 참조 | C# 7.2 이후 주소를 전달하여 복사 비용을 줄이되 내부에서 수정은 불가능(ReadOnly)하게 막는다. |
in 파라미터와 성능 최적화
크기가 큰 구조체를 일반적인 방식으로 전달하면 스택에 모든 데이터가 복사된다. 이때 in 키워드를 사용하면 “읽기 전용 주소”만 전달하므로 메모리 사용량과 속도 면에서 효율이 높다. 이는 고성능 수학 연산 라이브러리에서 필수적으로 쓰이는 기법이다.
값 전달과 참조 전달
클래스를 예시로 참조 타입의 복사는 다음과 같다.
-
값으로 전달된 클래스: 클래스 인스턴스의 주소 값을 복사하여 전달한다. 메소드 내부에서 객체의 속성을 바꾸면 원본도 바뀌지만 객체 자체를 새로 할당하면 원본 변수는 바뀌지 않는다.
-
ref로 전달된 클래스: 주소값을 담고 있는 변수 자체의 주소를 전달한다. 메소드 내부에서 new 키워드로 새 객체를 할당하면 원본 변수도 새로운 객체를 가리키게 된다.
가변 길이 매개 변수와 선택적 매개 변수
매개 변수의 방식은 다음과 같다.
-
params 키워드: 개수가 정해지지 않은 인수를 배열 형태로 받는다. 내부적으로는 배열 객체를 생성하므로 성능이 극도로 중요한 루프 안에서는 오남용하면 안된다.
-
선택적 매개 변수(Optional): 기본값을 설정하여 호출 시 인수를 생략할 수 있게 한다. 이는 메소드 오버로딩(Overloading)의 개수를 줄여주어 간결한 코드를 만든다.
메소드 인라인
런타임에 JIT 컴파일러는 성능 향상을 위해 매우 짧은 메소드 호출 코드를 호출부로 직접 복사해 넣는다.
-
효과: 스택 프레임을 생성하고 제거하는 오버헤드는 없앤다.
-
조건: 메소드 본문이 짧고, 가상 메소드가 아니어야 한다.