-
[iOS] - 참조 타입이 힙에 저장되는 원리(메모리&CPU 관점에서)iOS/iOS 2025. 2. 15. 11:35728x90반응형
스터디를 하다보니 구조체와 클래스에 대한 생각을 다시 하게 되었다.
그 중 참조 타입이 힙에 저장되는 원리를 메모리와 CPU관점에서 상세하게 과정이 갑자기 궁금해져서 정의를 명확히 하고자 다시 조사를 하기 시작했다.
일단 힙과 스택에 개념에 대해서 다시 정의해보자.
1. 힙(Heap)과 스택(Stack)의 개념
힙(Heap) 메모리
• 동적 할당 메모리 영역으로, 런타임에 크기가 결정되는 데이터가 저장됨.
• class 같은 참조 타입 객체는 힙에 저장되며, 여러 참조 변수가 같은 객체를 가리킬 수 있음.
• 명시적으로 deinit되거나, ARC에 의해 더 이상 참조되지 않을 때 해제됨.
스택(Stack) 메모리
• LIFO 구조로 함수 호출과 지역 변수(값 타입인 struct, enum, let 및 var 변수 등)가 저장됨.
• 빠르게 할당되고 해제되며, 함수 실행이 끝나면 해당 스택 프레임이 소멸됨.
이 정도는 힙과 스택의 너무나 기본적인 내용이다.
문제는 이렇게 알고만 있으나 실제 내부적으로 어떻게 저장되는지 과정을 모르는 것이다.
특정 코드를 빌드 했을 때 그 코드가 실제로 어떻게 저장되며 호출되는지 알아보자.
class Person { var name: String init(name: String) { self.name = name } } let person1 = Person(name: "Alice")클래스를 하나 생성해주고 클래스 밖에서 해당 클래스의 인스턴스를 만들었다.
여기서 CPU는 힙 메모리에서 객체를 저장할 공간을 요청하고, 운영체제가 적절한 크기의 메모리를 할당한다.
class는 다들 알다시피 참조타입이기 때문에, 인스턴스 자체는 힙에 저장되며, 저장된 주소(메모리 주소)가 반환된다.
그 주소는 그대로 스택에 저장되고, 힙에 있는 객체의 메모리 주소를 가진다.
CPU의 메모리 접근 과정
1. CPU 캐시 확인 → L1, L2, L3 캐시에 필요한 데이터가 있는지 먼저 확인.
2. 캐시에 없으면 RAM 접근 → RAM에서 해당 데이터를 로드함.
3. 메모리 주소를 따라 데이터 읽기 → 포인터를 따라가서 객체의 실제 데이터를 가져옴.
4. CPU 레지스터에 저장 후 연산 수행 → 데이터를 레지스터에 올려두고 연산 진행.
실제 CPU가 참조타입 객체를 읽는 과정
1. 스택에서 객체의 메모리 주소(포인터)를 찾음
• person1이 가리키는 힙의 메모리 주소(예: 0x12345678)를 가져옴.
2. 힙으로 이동하여 객체의 실제 데이터를 찾음
• 해당 주소로 이동하여 Person 객체 내부의 name 값을 확인.
3. 객체의 프로퍼티를 읽고 연산 수행
• name 프로퍼티 값을 가져와 CPU 레지스터에 올리고 사용.
과정은 이렇다. 한번 인스턴스 데이터를 사용하려면 이런 과정을 거치는 것이다. 심지어 힙 메모리는 동적할당이기 때문에, 스택 메모리에 비해 비용이 크다.(비연속적으로 데이터를 저장하기 때문에 메모리 단편화 문제가 발생하기 때문에 -> 이부분은 가상메모리를 활용하는 페이징 기법 등으로 해결 가능하긴함.)
이 부분을 공부하니 과거에 컴퓨터 구조를 공부했던 것을 다시 상기시키고, 잠시 머리에서 지웠던 부분을 다시 채울 수 있는 기회를 얻었다.
꼭 이부분은 확실히 짚고 넘어가야겠다...
'iOS > iOS' 카테고리의 다른 글
[iOS] - GCD(Grand Central Dispatch): 비동기, 병렬 처리, 스레드 관리 (0) 2025.05.19 [iOS] - CoreML, CreateML이란? (0) 2025.02.28 [iOS] - protocol을 사용하는 이유 (1) 2024.08.31 [iOS] - protocol이란? (0) 2024.08.31 [iOS] - 직렬과 동시(4/4) (3) 2024.03.16