Memory / ARC

ulls12·2024년 1월 3일
0

Swift TIL

목록 보기
26/60
post-thumbnail

메모리 구조 이해하기

Code 영역

  • 프로그램의 실행 코드가 저장되는 공간
  • 컴파일된 소스 코드와 프로그램의 명령어들이 저장되어 있다
  • 읽기 전용(Read-Only)이며, 프로그램이 실행되면서 수정되지 않는다

Data 영역

  • 전역 변수(global variables)와 정적 변수(static variables), 상수(constants)가 저장되어 있는 곳
  • 프로그램 시작 시 할당되고 프로그램이 종료될 때까지 유지된다

Stack 영역

  • 소스코드가 컴파일러에 의해 기계어로 변환되는 시점(Compile Time) 에 크기가 결정된다
  • 함수 호출과 관련된 정보를 저장할 때 사용된다
  • 함수가 호출될 때마다 해당 함수의 local variables, parameters, return address, 함수 호출에 필요한 기타 정보가 저장되는 곳
  • 함수가 실행을 마치면 해당 함수와 관련된 데이터가 스택에서 제거 된다
  • 스택은 (Last-In-First-Out, LIFO) 구조를 가지고 있다
  • 값타입(value Type)이 저장된다

Heap 영역

  • 프로그램 실행 중 동적으로 할당된 데이터가 저장되는 곳
  • 런타임 중에 메모리 할당이 필요한 경우 사용되며, 개발자가 직접 제어 할 수 있다
  • 힙에 저장된 데이터는 직접적으로 포인터를 통해 참조 된다
  • 힙은 스택과 달리 메모리의 자유 공간을 사용하며 데이터를 저장하므로, 크기나 수명에 대한 동적인 요구에 대응할 수 있다
  • 참조타입(reference Type)이 저장된다

ARC개념 이해하기

  • ARC: Automatic Refernece Counting
  • Heap영역의 객체 메모리를 자동으로 관리한다
  • ARC는 Heap 영역의 객체애 대한 강한 참조 count를 추적하고, 객체가 더 이상 필요하지 않을 때 (참조 count가 없을 때) 해당 객체에 대한 메모리를 자동으로 해제하는 방식

Strong Reference (강한 참조)

기본적으로 Swift에서 변수나 상수는 강한 참조를 한다. 객체에 대한 강한 참조 count가 증가되어 있다면, 해당 객체는 메모리에 유지된다.

class Person {
	var name: String
    init(name: String) {
    	self.name = name
    }
}
var person1: Person? = Person(name: "Alice") // 강한 참조
var person2 = person1
person1 = nil

person1이 nil이 되더라도 person2가 여전히 strong 참조를 가지고 있으므로 객체는 메모리에 유지된다

Circular Reference (순환 참조)

  • ARC 작동 방식의 특성상 두 개체가 서로를 강하게 참조하는 경우, 순환참조가 발생한다
  • 두 객체 모두 더이상 사용되지 않더라도 두 객체가 서로를 강하게 참조하는 경우, 강한 참조 count가 감소하지 않아, 메모리에서 해제되지 못하고 누수되는 문제가 발생한다
  • 이러한 문제를 해결하기 위해, 약한 참조(weak reference)와 미소유 참조(unowned reference) 같은 다른 참조 유형을 사용할 수 있다.
class Person {
    var name: String
    var pet: Pet?

    init(name: String) {
        self.name = name
    }
}

class Pet {
    var species: String
    var owner: Person?

    init(species: String) {
        self.species = species
    }
}

var person: Person? = Person(name: "Alice") // Person 클래스의 인스턴스를 생성
var pet: Pet? = Pet(species: "Dog") // Pet 클래스의 인스턴스를 생성

person?.pet = pet // Person 클래스의 pet에 Pet 인스턴스를 할당
pet?.owner = person // Pet 클래스의 owner에 Person 인스턴스를 할당

Weak Reference (약한 참조)

약한 참조는 강한 참조와 달리 객체의 참조 카운트를 증가시키지 않는다. 객체의 생명 주기에 영향을 주지 않으면서 참조를 유지 할 수 있다

class Person {
    var name: String
    weak var friend: Person? // 약한 참조
    init(name: String) {
        self.name = name
    }
}

var person1: Person? = Person(name: "Alice")
var person2: Person? = Person(name: "Bob")
person1?.friend = person2
person2?.friend = person1

// person1이 메모리에서 해제됨, 그에 따라 person1과 연결된 모든 객체의 참조 카운트가 감소됨

Unowned Reference (미소유 참조)

  • 약한 참조와 유사하지만, optional 값이 아니라, nil로 설정될 수 없다.
  • 만일 참조하는 객체가 이미 메모리에서 해제된 상태에서 접근하려 하면 runtime error가 발생되며, 사용 시점에 객체가 이미 해제되지 않았다고 확신할 수 있는 경우에 사용하여야 한다.
class Country {
    var name: String
    var capital: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capital = City(name: capitalName, country: self)
    }
}

class City {
    var name: String
    unowned var country: Country // 미소유 참조
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

궁금점

참조 Count를 감소시키는 방법은 어떤게 있을까? 간단하게 생각해보고 내일 내가 생각한 것과 일치하는지 확인해야겠다

profile
I am 개발해요

0개의 댓글