# 메모리의 구조 ## 메모리 구조 (주기억장치 RAM) ### ✏️ 프로그램 실행 순서 ![](https://i.imgur.com/XA1Wo6o.png) 프로그램의 정보를 읽어 메모리에 로드되는 과정. 프로그램을 실행하게 되면 OS(운영체제)는 `메모리(RAM)에 공간을 할당`한다. <br/> ### ✏️ 메모리 영역 RAM의 메모리 영역(공간)은 아래 4가지로 나뉜다. ![](https://i.imgur.com/Cy0PSLt.png) **▪️ 코드(Code) 영역** 개발자가 작성한 `소스코드`가 들어가는 부분. 실행할 프로그램의 코드가 저장되는 영역으로 `텍스트 영역`이라고도 부른다. 코드 영역은 실행 파일을 구성하는 명령어들이 올라가는 메모리 영역으로 함수, 제어문, 상수 등이 여기에 할당된다. <br/> **▪️ 데이터(Data) 영역** 전역 변수와 static 변수가 할당되는 영역. 프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리가 소멸된다. <br/> **▪️ 스택(Stack) 영역** 프로그램이 자동으로 사용하는 임시 메모리 영역. 함수 호출 시 생성되는 지역 변수와 매개변수가 저장되는 영역으로 함수 호출이 완료되면 사라진다. <br/> **▪️ 힙(Heap) 영역** 프로그래머가 할당/할당해제하는 메모리 공간. Swift에서는 ARC가 Reference Count를 통해 자동으로 할당 해제한다. 힙 메모리 영역에 할당하는 것을 `동적 할당(Dynamic Memory Allocation)`이라고도 한다. `class, closure` 등 참조 타입이 힙 영역에 할당된다. _런타임_ 에 크기가 결정된다. ![](https://i.imgur.com/AJOe0fd.png) > **🤔 Heap, Stack 영역** <br/> > Heap과 Stack 영역은 사실 같은 공간을 공유한다. Heap은 메모리 위쪽 주소부터 할당되고 Stack은 아래쪽부터 할당된다. 이에 따라 각 영역이 상대 영역을 침범하는 일이 발생할 수 있는데, 이를 각각 Heap Overflow, Stack overflow라고 한다. > > Stack 영역이 클 수록 Heap 영역이 작아지고, Heap 영역이 클 수록 Stack 영역이 작아진다. --- <br/> ## ARC(Automatic Reference Counting) ### ✏️ ARC란? 스위프트에서 앱의 메모리 사용을 추적/관리하는 방법. ARC를 통해 메모리 관리가 자동적으로 이루어지기 때문에 개발자는 메모리 관리를 직접적으로 생각할 필요가 없다. ARC는 클래스 인스턴스가 더 이상 필요하지 않을 때 해당 인스턴스가 사용한 메모리를 자동으로 할당 해제한다. 하지만, **ARC의 메모리 관리를 위해 코드 간의 관계에 대한 정보를 나타내야하는 경우**가 있다. **▪️ ARC 작동 방식** 새로운 클래스 인스턴스를 생성할 때마다 ARC가 메모리에 해당 인스턴스에 대한 정보를 저장한다. 이 메모리는 인스턴스의 타입에 대한 정보와 인스턴스와 결합된 저장 프로퍼티의 값을 포함하고 있다. 추가적으로, 더 이상 클래스 인스턴스가 필요없을 경우에는 ARC가 해당 인스턴스가 사용하던 메모리를 할당 해제하여 메모리를 다른 용도로 사용할 수 있게 한다. 이는 더 이상 클래스 인스턴스가 필요하지 않을 때 해당 인스턴스가 메모리 공간을 차지하지 않음을 보장한다. 하지만, ARC가 해제한 인스턴스가 여전히 사용 중이라면 더 이상 해당 인스턴스의 프로퍼티에 접근하거나 메서드를 호출하는 것이 불가능하다. 할당 해제된 인스턴스에 접근하는 경우 반드시 충돌이 발생할 것이다. 인스턴스가 필요한 동안에는 사라지지 않도록 하기 위해 ARC는 현재 얼마나 많은 프로퍼티, 상수 및 변수가 각각의 클래스 인스턴스를 참조하고 있는지 추적한다. ARC는 해당 인스턴스에 적어도 하나의 활성화된 참조가 존재하는 한 인스턴스를 해제하지 않을 것이다. 이를 가능하게 하기 위해 ARC는 프로퍼티, 상수 또는 변수에 클래스 인스턴스를 할당할 때마다 `강한 참조(Strong Reference)`를 만든다. 참조를 `강하다(Strong)`라고 표현하는 것은 해당 인스턴스를 확고하게 유지하기 때문이며, 강한 참조가 남아있는 한 클래스 인스턴스의 할당 해제를 허용하지 않는다. <br/> ### ✏️ MRC MRC는 Manual Reference Counting의 약자로 ARC가 등장하기 이전에 Objective-C에서 개발자가 직접 참조 관리를 하는 방식을 말한다. MRC에서도 ARC와 마찬가지로 Reference Count와 비슷한 Retain Count를 사용하여 참조 횟수를 관리한다. MRC의 경우 개발자가 직접 Count를 하기 때문에 인스턴스에 대한 RC에 접근할 수 있는 프로퍼티가 존재한다. (`retainCount`) MRC에서 레퍼런스의 증가에는 `alloc`, `new`, `copy`, `mutableCopy`, `retain` 등의 메서드를 호출하고 감소에는 `release`메서드를 호출한다. <br/> > 🤔**ARC와 Garbage Collection 비교** <br/> > Swift에서는 메모리 관리에 ARC를 사용하지만 다른 언어에서는 가비지 컬렉션(Garbage Collection)이라는 것을 사용하는 것 같다. <br/> > ARC의 경우 컴파일 타임에 MRC 때 개발자가 직접 작성하던 메모리 관리 코드를 자동으로 코드를 분석하여 적절하게 삽입해준다. 따라서 앱 실행 중 별도의 메모리 관리가 이루어지지 않는다. <br/> > GC(Garbage Collection)의 경우 프로그램 실행 중(런타임)에 동적으로 감시하고 있다가, 더 이상 사용할 필요가 없다고 여겨지는 인스턴스를 소멸(해제) 시킨다. <br/> ### ✏️ ARC를 이해해야 하는 이유 ARC 공식 문서에 명시된 **ARC의 메모리 관리를 위해 코드 간의 관계에 대한 정보를 나타내야하는 경우**가 있기 때문이라고 생각한다. 자동으로 메모리 관리를 해주지만, 인스턴스가 서로 강한 참조를 갖고 있는 **강한 순환 참조**가 발생한 경우 메모리 누수(memory leak)가 발생한다. 이러한 메모리 누수 등의 문제를 방지하기 위해 `메모리 참조 순환(Memory Reference Cycle)`에 대한 기본적인 내용을 알아야 효율적인 메모리 관리가 가능할 것이다. 코드 간의 관계에 대한 정보를 나타내는 키워드로는 `Strong, Weak, Unowned`가 있다. <br/> ### ✏️ Struct / Class 의 선택 기준 **안정성 측면에서 `가능한 한 struct를 사용`하라!👍** struct/class 모두 Data를 저장하고 behavior를 설계하는 것에 좋은 선택이지만 둘의 유사성으로 인해 어느 것을 선택할지 결정하는 것이 쉽지 않다. 앱에 새 데이터 타입을 추가할 때 적합한 옵션을 선택하는 것에 도움이 되도록 아래 4가지 권장 사항을 고려하자. * 기본적으로 struct를 사용한다. * Objective-C 상호 운용성이 필요할 때 class를 사용한다. * 모델링 중인 데이터의 ID를 제어해야 하는 경우 class를 사용한다. * 상속이 필요한 경우, 먼저 Protocol과 함께 struct를 사용하여 모델링한다. <br/> **◾️ 기본적으로 struct 사용** 구조체를 사용하여 일반적인 종류의 데이터를 나타낸다. Swift의 구조체는 다른 언어의 class로 제한되는 많은 기능이 포함되어 있다. 해당 기능은 저장 프로퍼티, 연산 프로퍼티 및 메서드가 포함될 수 있다. 또한 Swift 구조체는 프로토콜을 채택하여 프로토콜 필수 조건 구현을 통해 behavior를 얻을 수 있다. Swift 표준 라이브러리 및 Foundation은 숫자, String, Array, Dictionary와 같이 자주 사용하는 타입의 구조체를 사용한다. 구조체를 사용하면 앱의 전체 상태를 고려할 필요 없이 코드 일부에 대해 더 쉽게 추론할 수 있다. 구조체는 클래스와 달리 값 타입이므로 앱 흐름에서 발생한 로컬 변경 사항을 의도적으로 전달하지 않는 한 앱의 나머지 부분에 해당 변경 사항은 표시되지 않는다. 결과적으로 코드 섹션을 보고 해당 섹션의 인스턴스에 대한 로컬 변경 사항이 변경 사항과 관련된 함수 호출에서 보이지 않게 변경되는 것이 아니라 해당 섹션에서 명시적으로 만들어진다는 것을 더 확신할 수 있다. <br/> **◾️ Objective-C 상호 운용성이 필요할 때 class 사용** 만약 data를 처리해야 하는 Objective-C API를 사용하거나, Objective-C Framework에 class로 정의된 타입으로 data model을 맞춰야할 필요가 있다면, class와 class 상속이 필요하게 될지도 모른다. 예를 들어, 많은 Objective-C Framework는 사용자가 subclassing 할 것으로 예상되는 class들을 보여준다. <br/> **◾️ 모델링 중인 데이터의 Identity를 제어해야 하는 경우 class를 사용** Swift의 클래스는 참조 타입이기 때문에 Identity에 대한 내장된 개념이 있다. 이것은 두 개의 서로 다른 클래스 인스턴스가 각각의 프로퍼티에 저장된 값이 동일한 경우에도 항등 연산자(===)에 의한 연산에서 서로 다른 것으로 간주된다는 것을 의미한다. 또한 앱 전체에서 클래스 인스턴스를 공유할 때 해당 인스턴스에 대한 변경 사항은 해당 인스턴스에 대한 참조를 보유하는 코드의 모든 부분에서 볼 수 있음을 의미한다. 인스턴스가 이러한 종류의 Identity를 가져야 하는 경우 클래스를 사용하라. 일반적인 class 사용 사례는 file handles, network connection 및 CBCenteralManager와 같은 shared hardware intermediaries이다. 예를 들어 로컬 데이터베이스 연결을 나타내는 유형이 있는 경우 해당 데이터베이스에 대한 액세스를 관리하는 코드는 앱에서 볼 때 데이터베이스 상태를 완전히 제어해야 한다. 이 경우 클래스를 사용하는 것이 적절하지만 공유 데이터베이스 개체에 액세스할 수 있는 앱의 부분을 제한해야 한다. > **❗️ Important** <br/> > Identity를 주의해서 다뤄야한다. 앱 전체에서 클래스 인스턴스를 광범위하게 공유하면 논리 오류가 발생할 가능성이 높아진다. 많이 공유되는 인스턴스를 변경한 결과를 예상하지 못할 수 있으므로 이러한 코드를 올바르게 작성하는 것이 더 중요하다. <br/> **◾️ Identity를 갖더라도 제어할 필요가 없는 경우 struct 사용** 제어할 수 없는 Identity를 가진 entity에 대한 정보가 포함된 데이터를 모델링할 때 구조체를 사용한다. (entity == 어떤 데이터의 집합) 예를 들어 원격 데이터베이스를 참조하는 앱에서 인스턴스의 Identity는 외부 entity가 완전히 소유하고 식별자로 통신할 수 있다. 앱 모델의 Consistency가 서버에 저장되어 있는 경우 레코드를 식별자가 있는 구조로 모델링할 수 있다. _-> 추후 서버와 통신에 대해 학습 하면 추가로 학습해보자._ <br/> **◾️ 상속이 필요한 경우, 먼저 Protocol과 함께 struct를 사용하여 모델링** 구조체와 클래스는 모두 상속 형식을 지원한다. 구조체와 프로토콜은 프로토콜만 채택할 수 있고 클래스를 상속할 수는 없다. 그러나 클래스 상속으로 구출할 수 있는 상속 class inheritance 같은 것들은 프로토콜 상속과 구조체를 사용하여 모델링 할 수도 있다. 처음부터 상속 관계를 구축하는 경우 프로토콜 상속이 선호된다. 프로토콜은 클래스, 구조체 및 열거형이 채택하는 것을 허용하지만 클래스의 상속은 클래스 간에서만 허용된다. 데이터 모델링 방법을 선택할 때 먼저 프로토콜 상속을 통해 데이터 타입의 계층 구조를 구축한 다음, 해당 프로토콜을 구조체에 채택해보자. <br/> [참조 문헌] 1. [CS 메모리 구조 - Jinshine 블로그](https://jinshine.github.io/2018/05/17/%EC%BB%B4%ED%93%A8%ED%84%B0%20%EA%B8%B0%EC%B4%88/%EB%A9%94%EB%AA%A8%EB%A6%AC%EA%B5%AC%EC%A1%B0/) 2. [Swift Language Guide - ARC](https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html) 3. [날진 블로그 - ARC 뿌시기](https://sujinnaljin.medium.com/ios-arc-%EB%BF%8C%EC%8B%9C%EA%B8%B0-9b3e5dc23814) 4. [개발자 소들이 - 메모리 관리 MRC/MRR](https://babbab2.tistory.com/28) 5. [Clint Jang - RC, ARC, MRC](https://medium.com/@jang.wangsu/ios-swift-rc-arc-%EC%99%80-mrc-%EB%9E%80-%EA%B7%B8%EB%A6%AC%EA%B3%A0-strong-weak-unowned-%EB%8A%94-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%A0%81%EC%96%B4%EB%B4%A4%EC%8A%B5%EB%8B%88%EB%8B%A4-988a293c04ac) 6. [JNomaKit velog - Struct/Class 선택기준](https://velog.io/@yohanblessyou/Struct%EC%99%80-Class-%EC%A4%91-%EB%AC%B4%EC%97%87%EC%9D%84-%EC%93%B8%EA%B9%8C) 7. [Apple Developer Article - struct/class 선택하기](https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes)