Understanding Swift performance - 스택, 힙

고라니·2024년 2월 12일
0

TIL

목록 보기
60/67

이전 글에서 Generic에대해 정리 해보았고 다음에 Generic의 성능에 대해 알아보기로 했었다.
그래서 WWDC 2016 Understanding Swift performance를 보게 되었다.
역시 좋은 내용이었고 설명도 친절했다. 굉장히 잘 정리되어 있는 글들이 많아서 따로 정리하지는 않을것이다.
다만 영상을 보면서 추가적으로 궁굼한게 생겼고 그 궁굼증에 대해 작성해려고 한다.

주의: 궁굼증에대해 나름 찾아보았지만 틀릴 수 있다!

스택(Stack) 영역

메모리의 스택영역은 아주 간단한 작동 방식으로 힙영역의 작동 방식과 비교했을 때 성능이 좋다고 한다. 또한 컴파일 시점에 스택영역에 할당 될 크기를 미리 결정한다고 한다. 만약 예상치 못하게 할당된 크기를 초과할 경우 '스택오버플로우'가 발생한다.

어떻게 필요한 스택 영역의 크기를 계산할까?

그런데 컴파일 시점에 어떤 기준으로 어떻게 스택의 크기를 미리 계산하고 할당하는 것일까?

  • 컴파일러는 소스코드를 분석하면서 각 구조체, 함수의 프로퍼티, 지역변수, 매개변수, 리턴값 등의 타입과 개수를 파악한다.

  • 각 타입별로 필요한 메모리 크기를 알고 있으므로 필요한 메모리 크기를 계산한다.

  • 이러한 정보들을 기록하는데 이를 스택 프레임(Stack Frame)이라고 부른다. 스택 프레임은 스택 영역에 할당될 메모리, 구조, 크기를 정의한다.

쉬운 이해를 위해 예시 상황으로 알아보자.
A함수가 Int형 변수 a, b를 사용하고 B함수가 Double형 변수 c를 사용한다고 가정해보자.
컴파일러는 코드를 분석하면서 A함수가 a: 4비트, b: 4비트로 총 8비트, B함수가 c: 8비트로 총 8비트 필요한 것을 알 수 있다. 즉 최소 8비트 이상의 스택 영역이 필요하다는것을 알 수 있다.
만약 A함수가 B함수를 호출하는 경우 최소 16비트가 필요하다는것을 알 수 있다.

즉 스택 영역의 크기 예측은 컴파일러가 프로그램의 소스 코드를 분석하여, 스택 영역에 필요한 메모리 크기의 최대값을 계산하는 과정이며, 컴파일러는 함수의 호출 관계, 지역 변수의 선언 재귀 함수의 깊이 등을 고려하여, 가장 깊은 기준으로 스택 영역의 크기를 예측하는 것이다.

크기를 미리 계산하는데 왜 스택오버플로우가 발생할까?

설정된 스택 영역의 할당량을 넘는 경우 스택오버플로우가 발생한다.
그런데 코드 분석을 통해 크기를 미리 예측 했는데 왜 스택오버플로우가 발생할까?

스택 영역의 크기 예측은 컴파일시점에 파악 가능한 데이터들의 크기만 알 수 있다.
그렇기 때문에 런타임 동안 발생하는 여러 상황은 컴파일 시점에 미리 예측할수 없다.
그렇기 때문에 런타임 동안 스택 오버플로우가 발생할 수 있는 것이다.

스택영역에 할당될 구조체나 함수는 힙영역에 할당될 참조타입을 값들을 가질 수 있고. 해당 값들은 런타임 동안 크기가 변할 수 있기 때문이다.

예시 상황으로 알아보자
intArr라는 String 배열이 있다고 가정하자
a라는 함수는 intArr를 for문을 통해 해당 문자열을 출력한다.
이 때 런타임중에 intArr이 변할 수 있다면 컴파일 시점에 a함수가 필요한 메모리 크기를 예측할 수 없다.

구조체라고 해도 참조를 조심하자

Understanding Swift performance 영상을 보면 아래와 예시를 보여준다.
구조체도 값이 공유될 수 있음을 설명하는 예시는 아니지만 이 예시를 보면서 든 생각이다.

구조체는 값타입이다. 값을 다른 속성에 할당하면 복사된다. 반대로 클래스는 참조값이다. 다른 속성에 값을 할당해도 복사되지 않고 같은 인스턴스를 참조하게 된다. 그리고 값을 수정하면 수정된 값은 공유된다. 그렇기 때문에 주의가 필요한데
구조체 또한 주의해야 하는 경우가 발생할 수 있다.

위의 예시를 보자
Label은 구조체로 구현되어 Stack에 할당된다.
label1은 Label을 초기화 해서 값을 가지고
label2에 label1을 할당한다.
이 때 Label은 값타입이기 때문에 복사된다.
그렇지만 text는 String, font는 UIFont로 힙에 저장될 수 있다.
결국 label1과 label2는 각각의 Label을 가지고 있지만 내부 속성은 같은 값을 참조하게 될 수 도 있다.

이 때 label1의 text를 "bye"로 수정하면 label2의 text도 "bye"가 될까?
(상황에 따라 다를 수 있다. String이라고 항상 힙에 저장되는건 아니라고 한다!)
아무튼 주의해야 할 필요가 있다.


여기까지!

profile
🍎 무럭무럭

0개의 댓글