Swift/Swift 문법

[ARC 1] Swift의 메모리 관리 모델

내일은개발천재🎵 2022. 12. 30. 22:52

복습) 값 형식과 참조 형식 (711)

  1. 값 형식 (Value Type)
    • Baisic Type, 튜플, 구조체, 열거형, 컬렉션 등이 해당된다.
    • Stack 영역에 값이 저장된다.
    • 필요시에는 항상 메모리의 값이 복사되어 전달된다.
    • 사용이 끝나면, Stack프레임에서 알아서 제거되므로 별도로 메모리 관리를 할 필요 없다.
  2. 참조 형식 (Reference Type)
    • 클래스, 클로저가 해당된다.
    • 필요시에 항상 메모리의 주소를 전달한다. (Heap의 주소를 Stack에 저장)
    • Heap 영역에 실제 값들이 저장된다.
    • **RC(Reference Counting, 참조 카운팅)**을 통해 메모리를 관리한다.
      • Swift에서 사용하는 ARC 모델

복습) 메모리 구조 - 코데힙스

  1. 코드영역
    • CPU가 실행할 수 있는 실질적 명령어들이 모여있는 공간 (모든 코드, 프로그램이 존재)
    • get Only
    • 코드영역에 필요한 데이터들이 데이터, 힙, 스택 영역에 저장되어있다.
      • 데이터 = 전역 변수, 타입 속성 등 공통으로 공유되는 데이터
      • 힙 = 동적할당으로 크기가 크고, 관리할 필요가 있는 데이터
      • 스택 = 함수 실행을 위한 임시 공간
  2. 데이터 영역
    • 공통으로 공유하기 위한 데이터를 저장한다.
      • 전역 변수, 타입속성을 저장한다.
      • 붕어빵 틀이 저장되어 있다.
    • 앱이 실행되는 동안은 불변의 성질을 갖는다.
  3. 힙 영역
    • 인스턴스를 동적으로 할당한다. (동적할당)
      • 일반적으로 긴 시간동안 저장한다.
    • 필연적으로 느릴 수밖에 없다.
    • 관리하지 않으면 메모리 누수 현상이 발생해 앱이 종료될 수 있다.
      • 메모리 누수 현상(Memory Leak): 메모리가 제거되지 않는 현상
      • 개발자가 직접 관리해주어야한다.
  4. 스택 영역
    • 함수 실행을 위한 임시적 공간이다.
    • 크기가 작고 빠르게 사용하기 위한 데이터가 저장되어 있다.
    • 자동으로 메모리 관리가 이루어진다.

언어 별 메모리 관리 기법

  • 자바의 GC (Garbage Collector)
    • 런타임에 힙 영역을 자동으로 스캔해서 알아서 관리해줌
    • 스캔하는 속도가 있어서 느려짐! (언제 어느 시점에 이루어지는지는 알 수 없음)
  • objective - c
    • 참조 숫자(RC)를 세는 것을 통해 메모리 관리 / 컴파일 시 메모리 해제시점 결정
    • 수동으로 숫자 세는 것이 MRC (개발자가 수동으로 계산)
    • 자동으로 숫자 세는 것이 ARC
      • 컴파일러가 알아서 코드를 심어줌메모리 해제가 잘 되도록, 이론을 잘 알고 사용해야함.
      • → 메모리 관리를 알아서 해주는게 아니고 숫자를 제대로 세 준다는것임!
  • Swift
    • ARC (Automatic RC)
      • 메모리를 수동으로 관리할 수 없다.

ARC 작동 원리

  • 클래스의 인스턴스가 생성될 때마다 ARC는 인스턴스에 대한 정보를 저장한다.
    • 인스턴스, 관련 프로퍼티 값, 인스턴스 타입에 대한 정보를 저장한다.
  • 인스턴스가 더이상 필요하지 않으면, ARC는 사용된 메모리를 할당 해제한다.
    • 인스턴스에 참조가 하나라도 존재한다면, ARC는 메모리를 할당 해제하지 않는다.
    • → 이를 위해 클래스 인스턴스를 할당할 때마다 강한 참조를 만들게 된다. 참조는 해당 인스턴스를 유지하고, 강한 참조가 남아있는 한 할당 해제를 허용하지 않기 때문에 강한 참조라고 부른다.
  • → 클래스 인스턴스가 필요하지 않을 때 메모리 공간을 차지하지 않는다.

ARC와 MRC

1. ARC

class Point {
	var x, y: Double
	func draw() {}
}

let point1 = Point(x: 0, y: 0)
let point2 = point1
point2.x = 5
//use point1
//use point2

 

2. MRC

class Point {
	**var refCount: Int**
	var x, y: Double
	func draw() {}
}

let point1 = Point(x: 0, y: 0)
let point2 = point1
**retain(point2)**
point2.x = 5
//use point1
**release(point1)**
//user point2
**release(point2)**
  • 이전 언어들은 MRC와 같이 메모리를 수동으로 관리했다.
  • 현대 언어의 경우 자동 메모리 관리 모델을 사용한다.
    • 컴파일러가 retain() ⇒ release() 해제 코드를 삽입한다고 생각
  • 이전 언어들은 메모리를 수동 관리했음 (MRC)
  • 현대 언어의 경우 자동 메모리 관리 모델 사용
    • Swift는 컴파일러가 retain()할당 코드 → release() 해제 코드를 삽입한다
    • 메모리 관리에 대한 실수를 방지하여 프로그램의 안정성이 증가된다.

ARC 기반

  • 나를 가리키는 소유자가 없으면 해제된다는 원칙을 가지고 있다.
  1. 소유 정책
    • 하나 이상의 소유자가 있는 경우 메모리에 유지됨
  2. 참조 카운팅
    • 나를 가리키는 소유자 카운팅

ARC 동작

  • 어떻게 자동 참조 카운팅이 동작하는가?
class Person {
	let name: String
	init(name: String) {
		self.name = name
		print("\\(name) is being initialized")
	}
	deinit {
		print("\\(name) is being deinitialized")
	}
}

var soi: Person? = Person(name: "지원") // retain(soi), RC: 1
var reference: Person?
var reference = Person(name: "John") // retain(reference), RC: 2
soi = nil // release(soi), RC: 1
reference = nil // release(reference), RC: 0
  • 예전 언어의 경우 모든 메모리를 개발자들이 수동 관리했다. (retain, release)
  • 현대적 언어는 대부분 자동 메모리 관리 모델을 사용하며, Swift의 경우 컴파일러가 retain() → release()코드를 삽입한다고 보면된다.
    • 프로그램 메모리 관리에 대한 안정성이 증가했다.

 

GitHub - JIWON1923/Today-I-Learend

Contribute to JIWON1923/Today-I-Learend development by creating an account on GitHub.

github.com

앨런님의 Swift 강의 및 애플 공식 문서를 보며 작성한 글입니다.