[iOS 3주차] ARC(Automatic Reference Counting)

황석범·2024년 11월 8일
0

내일배움캠프_iOS_5기

목록 보기
15/76

ARC(Automatic Reference Counting)

  • Reference Type 의 인스턴스 메모리 관리를 자동으로 해주는 기능입니다.
    • Value Type 의 인스턴스는 ARC 가 관리하지 않습니다.
  • 메모리 관리를 직접 하지 않아도 ARC 가 자동으로 메모리 관리를 처리합니다.
  • Reference Type 의 인스턴스를 참조할 때, 참조카운트가 증가하며, 이를 strong 참조라고 합니다.
  • 참조카운트의 증가를 원하지 않는 경우 weak 또는 unowned 참조를 사용할 수 있습니다.

ARC 동작 방식

  1. 인스턴스 생성과 메모리 할당
    • class 의 새로운 인스턴스를 생성할 때 마다 ARC 는 해당 인스턴스에 대한 정보를 저장할 메모리 공간을 할당합니다.
    • 이 공간에는 인스턴스의 타입 정보프로퍼티의 값이 저장됩니다.
  2. 참조 카운트 관리
    • ARC는 사용중인 인스턴스가 메모리에서 해제되지 않도록, 몇개의 프로퍼티, 상수, 변수가 인스턴스를 참조하고 있는지 추적합니다.
      • 참조 시작시: 카운팅 +1
      • 참조 종료시: 카운팅 -1
      • 최종적으로 참조카운트가 0이 되면 인스턴스는 메모리에서 해제됩니다.
  3. 메모리 해제
    • 참조카운트가 0이 된 인스턴스는 더이상 필요하지 않기 때문에, ARC가 해당 인스턴스가 사용했던 메모리를 해제합니다.
      • 만약 참조 카운트가 0이 되기전에 인스턴스가 해제되면, 이후 그 인스턴스에 접근할 경우 앱이 크래시가 발생할 수 있습니다.

ARC 동작 시기

  • ARC는 컴파일타임 에 인스턴스의 참조 카운트를 증가 또는 감소시키는 코드를 자동으로 삽입합니다.

Memory Leak

  • 메모리누수
  • 사용이 끝난 인스턴스가 메모리에서 해제되지 않고 남아있는 현상입니다.
  • 이렇게 메모리 공간이 불필요하게 사용되면 성능 저하가 발생할 수 있습니다.

강한순한참조(Strong Reference Cycle)

  • iOS에서 자주 발생하는 Memory Leak 의 원인중 하나입니다.

class Person {
	let name: String
    init(name: String) { self.name = name}
    var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
	let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized")}
}
  • PersonApartment 는 서로를 참조하고 있기 때문에 순환 참조가 발생할 수 있습니다.
 
var john: Person?
var unit4A: Apartment?
 
john = Person(name: "John") // RC : 1
unit4A = Apartment(unit: "4A") // RC : 1


john!.apartment = unit4A // john의 아파트에는 unit4Af를 할당해서 RC가 1 올라서 2가 됨
unit4A!.tenant = john // unit4A의 거주자에는 johndㅡㄹ 할당해서 RC가 1 올라서 2가 됨


john = nil // 참조가 종료되었으므로 Person instance RC에 -1을 함
unit4A= nill // 참조가 종료되었으므로 APartment instance RC에 -1을 함

// 하지만 Person, Apartment의 instance RC는 2에서 1로 줄었을 뿐입니다.

  • Person instance와 Apartment instance의 RC가 1로 사용이 종료되었지만 메모리에서 해제되지 않음.
  • 강한 참조로 서로를 참조한다고 하여 강한순한참조라고 합니다.

강한순한참조 해결방법

  • 참조 카운트를 올리지 않으면 강한순한참조를 방지할 수 있습니다.
  • 참조 카운트를 올리지 않기 위해서는 strong 이 아닌 weak , unowned 를 사용하면 됩니다.

class Person {
    let name: String
    init(name: String) { self.name = name }
    weak var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}


class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var brody: Person?
var unit100A: Apartment?

brody = Person(name: "brody") // Person instance RC : 1
unit100A = Apartment(unit: "100평 아파트") // Apartment instance RC : 1


brody.apartment = unit100A // Person의 apartment가 weak 이기 때문에 RC가 올라가지 않음 RC : 1
unit100A.tenant = brody // Apartment의 tenant가 weak이기 때문에 RC가 올라가지 않음 RC : 1

brody = nil // Person instance RC 1 감소 -> RC : 0
unit100A = nil // Apartment instance RC에 1 감소 -> RC : 0
// RC가 0이 되어서 Person instance 메모리에서 해제, Apartment instance 메모리에서 해제

객체를 참조하는 방법 3가지

  1. strong
  • 강한 참조
  • Dufault 값 입니다!
  • 객체를 참조 시작하면 참조카운트가 1 올라감
  • 객체 참조가 종료되면 참조카운트가 1 내려감
  1. weak
  • 약한 참조
  • 객체를 참조하면 참조카운트가 변하지 않음
  • 객체 참조가 종료되도 참조카운트가 변하지 않음
  • nil을 허용
  1. inowned
  • 미소유 참조
  • 객체를 참조하면 참조카운트가 변하지 않음
  • 객체 참조가 종료되도 참조카운트가 변하지 않음
  • nil이면 크래시 발생
profile
iOS 공부중...

0개의 댓글

관련 채용 정보