=> Swift에서는 Auto Reference Counting, 즉 ARC를 통해 메모리를 관리하는데 ARC란 Swift에서 컴파일 타임에 자동으로 retain, release를 삽입해서 런타임에 reference count를 증감시키다가 count가 0이 되면 deinit을 통해 메모리를 해제시키는 방식으로 메모리를 관리해주는 것입니다. 인스턴스의 주소 값이 변수에 할당될 때 RC값이 증가하면 이것을 '강한 참조'라고 하는데 두 객체가 서로 강한 참조를 하며 서로의 RC값을 증가시키면 순환참조가 일어나게 되고 이 때는 weak나 unowned를 통해 참조를 하더라도 RC 값을 증가시키지 않도록 해야지 메모리에서 정상적으로 해제되서 메모리 누수를 방지할 수 있습니다.
=> weak와 unowned는 모두 RC값을 증가시키지 않아 강한 순환 참조를 해결할 수 있지만 참조하던 인스턴스가 메모리에서 해제된 경우 weak는 자동으로 nil이 할당되어 메모리가 해제되지만 unowned는 nil을 할당받지 못하고 해제된 메모리 주소값을 계속 들고 있기 때문에 에러가 발생할 수 있어 위험성이 높습니다.
=> ARC를 효과적으로 관리하기 위해서는 강한 참조 순환을 해결해야 합니다. 이를 해결 하기 위해서는 weak와 unowned를 사용하고, 클로저 안에서는 두 참조를 캡처 리스트(capture list)를 통해 사용합니다. 그리고 불필요한 객체를 메모리에서 해제 해주는것도 효과적인 관리 방법 중 하나인데 이를 위해 deinit 메서드를 활용하거나 앱이 메모리 경고를 받았을 때 호출되는 didReceiveMemoryWaring 메서드를 활용합니다.
프로그램이 실행되면 운영체제는 메모리에 해당 프로그램을 위한 공간을 할당해 줌
해당 공간은 코드, 데이터, 힙, 스택 총 4가지 영역으로 나눠져 있음
코드 - 우리가 작성한 소스 코드가 기계어 형태로 저장, 컴파일 타임에 결정되고, 중간에 코드가 변경되지 않도록 Read-Only 형태로 저장됨
데이터 - 전역변수, static 변수가 저장, 일반적으로는 프로그램 시작과 동시에 할당되고, 프로그램이 종료 되어야 메모리에서 해제, 실행 도중 변수 값이 변경될 수 있기 때문에 Read-Write로 저장
- 다만 Swift에서 static을 포함한 전역변수는 기본 동작이 lazy이기 때문에 프로그램 시작과 동시에 할당되어 메모리에 올라가진 않고 해당 값에 처음 접근할 때 값이 할당되어 메모리에 올라감
힙 - 프로그래머가 할당/해제 하는 메모리 영역, malloc, calloc으로 힙에 메모리를 할당할 수 있으며, 이를 '동적 할당' 이라고 함, 사용하고 난 후에는 반드시 메모리 해제를 해줘야 하고 그렇지 않으면 메모리 누수가 발생, 유일하게 런타임 시 결정되기 때문에 데이터의 크기가 확실하지 않을 때 사용
- Swift에서 클래스 인스턴스, 클로저 같은 참조 타입의 값들은 힙에 자동 할당됨
- 해제는 ARC를 통해 힙에 할당된 메모리가 더 이상 참조되지 않으면 자동으로 해제해줌
- 장점으로는 메모리 크기에 대한 제한이 없음
- 단점으로는 할당 및 해제 작업으로 인한 속도 저하, 힙 손상(이중 해제, 해제 후 사용 등) 작업으로 인한 속도 저하, 힙 경합(두 개 이상 쓰레드가 동시에 접근하려 할 때 Lock이 걸림)으로 인한 속도 저하, 메모리를 직접 관리해야 하는 것들이 있음 -> 여기서 속도 저하란 막 엄청 느리다는 것이 아니고 스택보다 상대적으로 느리다는 개념
- 자신의 영역 외로 확장하려다보면 힙 오버 플로우 발생
스택 - 함수 호출 시 함수의 지역변수, 매개변수, 리턴 값 등등이 저장되고, 함수가 종료되면 저장된 메모리도 해제됨, 컴파일 타임에 결정되기 때문에 무한히 할당할 수 없음, LIFO(Last In, First Out) 데이터 구조
- 장점은 CPU에 의해 관리되고 최적화 되서 속도가 매우 빠르고 메모리를 직접 해제를 해주지 않아도 됨
- 단점은 메모리 크기에 대한 제한이 있고, 지역 변수만 액세스 가능
- 스택에 너무 많은 메모리를 할당하게 되면 스택 오버 플로우가 발생함 - iOS에서 스택 오버 플로우가 발생하면 어플이 죽어버림
힙과 스택은 같은 메모리 영역을 공유 - 힙 영역은 낮은 메모리 주소부터 할당, 스택 영역은 높은 메모리 주소부터 할당