내일배움캠프 iOS

UIKit) TIL # 33 메모리 관리 이해

yjuni22 2024. 12. 4. 23:02

메모리와 디스크

메모리 - RAM

  • RAM 은 휘발성 메모리이다. 즉, 데이터를 영구적으로 저장하지 않는다. 일시적인 저장에 사용한다.
  • → 앱도 결국 데이터 덩어리이기 때문에, 실행을 시키면 메모리에 올라간다.
  • → RAM 의 용량이 클 수록, 동시에 실행시킬 수 있는 앱의 총량이 높아진다고 생각할 수 있다.
  • → 그렇기 때문에 메모리에 저장된 데이터는 앱이 메모리에서 내려올 때 같이 내려오게 되는 것.
  • → 앱 실행중에 메모리에 저장된 데이터들은 앱을 종료하면 함께 삭제된다. (휘발된다)

디스크 

  • 영구적인 데이터를 저장하는 곳. 비휘발성 장치.
  • → 앱 실행중에 디스크에 저장된 데이터들은 앱을 종료해도 디스크에 남는다.
  • 파일, 문서, 프로그램 등 상대적으로 용량이 큰 정보들을 담을 수 있다.
  • 메모리에 비해 속도가 느리다.
  • UserDefaults, CoreData 를 활용해서 디스크에 데이터를 저장할 수 있다.

Garbage Collector (GC)

- Garbage Collector 는 메모리 관리를 돕는 시스템 중 하나. 대표적으로 Java 에서 GC 를 사용한다.

- 쓰레기 청소부, 사용하지 않는 메모리를 처리해줌, 쌓이게 되면 메모리 누수가 발생함

Reference Counting(RC)

인스턴스를 참조하고 있는 소유자의 갯수

참조 카운팅 > 0 이면 메모리에 살아있음, 0 = 메모리에서 삭제

 

class MyClass {
    init() {
        print("MyClass 생성")
    }
    deinit {
        print("MyClass 소멸")
    }
}

// RC = 1
var myClass: MyClass? = MyClass()

// RC = 2
var myClass2 = myClass

// RC = 2-1 = 1
myClass = nil

ARC ( Automatic Reference Counting )

ARC 는 Swift 의 메모리 관리 시스템. Java 에 GC 가 있다면 Swift 에는 ARC 가 있음.

자동으로 관리해줌

  • Reference Count 를 자동으로 계산. (Automatic)
    • 객체가 생성될 때 RC 가 1 로 설정
    • 객체가 다른 변수나 속성에 할당되어 참조될때마다 RC 가 1 씩 증가
    • 객체에 대한 참조가 해제될때마다 RC 가 감소
    • RC 0 이 되면 더 이상 사용되지 않는 것으로 간주되어 메모리에서 해제.

MRC 

- MRC 는 Objective-C 에서 사용하는 메모리 관리 시스템.

- Reference Count 를 개발자가 코드로 직접 계산. (Manual)

 

ARC 로 잡아내지 못하는 메모리 누수 상황이 발생할 수 있기 때문에, 개발자는 메모리 관리 방법을 반드시 알아야 합니다.

 

약참조 - weak

 

강참조 - 일반적인 참조 방식

 

클로저의 캡처링 개념

class Adam {
    let mbti = "ENTJ"
    init() {
        print("클래스 생성")
    }
    deinit {
        print("클래스 소멸")
    }
}

// adam rc = 1
var adam: Adam? = Adam()

// 클로저 내부에서 adam 캡처. rc 1 증가. adam rc = 2
let printMbti: () -> () = { [adam] in
    guard let adam else { return }
    print("adam's mbti = \(adam.mbti)")
}

printMbti()

// adam rc = 2-1 = 1
adam = nil

 

weak 약한참조

class Adam {
    let mbti = "ENTJ"
    init() {
        print("클래스 생성")
    }
    deinit {
        print("클래스 소멸")
    }
}

// adam rc = 1
var adam: Adam? = Adam()

// 클로저 내부에서 adam 캡처.
// weak 참조 했으므로 rc 가 증가하지 않음. adam rc = 1
let printMbti: () -> () = { [weak adam] in
    guard let adam else { return }
    print("adam's mbti = \(adam.mbti)")
}

printMbti()

// adam rc = 1-1 = 0
adam = nil

 

자세한 내용 블로그 참고

https://noguen.com/120

 

[iOS][Swift] 클로져 캡쳐에 대한 이해

개요 Swift를 공부하다보면 lambda와 비슷한 개념으로 클로져(Closure)라는게 나온다. 내용 자체는 익명 함수와 비슷한데, 초반부터 나오는 캡쳐(Capture)라는 용어가 굉장히 이해하기가 힘들었다. ▼

noguen.com

 

 

 

순환 참조

 

A 가 B 를 참조하고 (A→B),

B 가 A 를 참조해서 (B→A), 서로가 서로를 참조하는 상황

일반적으로 순환 참조는 메모리 누수를 발생시키는 대표적인 사례

class Person {
    var pet: Dog?
    init() {
        print("Person 클래스 생성")
    }
    deinit {
        print("Person 클래스 소멸")
    }
}

class Dog {
    var owner: Person?
    init() {
        print("Dog 클래스 생성")
    }
    deinit {
        print("Dog 클래스 소멸")
    }
}

// person rc = 1
var person: Person? = Person()
// dog rc = 1
var dog: Dog? = Dog()

// dog rc = 2
person?.pet = dog
// person rc = 2
dog?.owner = person

// person rc = 1
person = nil
// dog rc = 1
dog = nil