-
메모리 관리 RC, Reference Counting개발...................../TIL 2024. 7. 10. 11:32
컴맹이어서 메모리가 뭐고, RAM이 몇이냐고 물어봤을 때 넹??그게 몬가요,,;; 내가 앱을 만들고자 하니 메모리 관리의 필요성이 있으니 수년간 이해해보려던 메모리와 디스크에 대해 이번에야 저장됐다. 늘 메모리에 있다가 디스크로 넘어간..^^암아도..?
메모리
- 일반적으로 RAM 을 말하는 경우가 많다.
- 맥북에서도 몇 GB 짜리 RAM 을 사용하는지 볼 수 있다.
- RAM 은 휘발성 메모리이다. 즉, 데이터를 영구적으로 저장하지 않는다. 일시적인 저장에 사용한다.→ 앱도 결국 데이터 덩어리이기 때문에, 실행을 시키면 메모리에 올라간다.→ RAM 의 용량이 클 수록, 동시에 실행시킬 수 있는 앱의 총량이 높아진다고 생각할 수 있다.
- → 그렇기 때문에 메모리에 저장된 데이터는 앱이 메모리에서 내려올 때 같이 내려오게 되는 것.
- → 앱 실행중에 메모리에 저장된 데이터들은 앱을 종료하면 함께 삭제된다. (휘발된다)
- 디스크보다 속도가 빠르다. (CPU 가 디스크보다 메모리에 더 빨리 접근할 수 있다.)
- 디스크에 비해 용량이 작다. (보통 8GB, 16GB, 32GB)
- EEPROM 과 같은 비휘발성 메모리도 있다. 아이폰은 이곳에 장치의 일련번호 및 하드웨어 정보를 저장한다.
디스크
- 영구적인 데이터를 저장하는 곳. 비휘발성 장치.
- → 앱 실행중에 디스크에 저장된 데이터들은 앱을 종료해도 디스크에 남는다.
- 파일, 문서, 프로그램 등 상대적으로 용량이 큰 정보들을 담을 수 있다.
- 메모리에 비해 속도가 느리다.
- UserDefaults, CoreData 를 활용해서 디스크에 데이터를 저장할 수 있다.
다음 주어진 상황들에서, 메모리를 활용하는게 좋을지 디스크를 활용하는게 좋을지 생각해봅시다. 정답은 드래그
- 전화번호부 앱에서 친구의 이름, 전화번호 정보 데이터. 디스크(실행마다 날아간다고 생각해봐라)
- 카운터 앱 개발할 때 사용했던 number 변수. 메모리(실행해서 초기부터 해도 되니까 굳이?)
- 스테이지가 있는 게임 앱에서 유저가 몇 스테이지까지 클리어했는지 정보. 디스크(마지막 스테이지에서 날아갔다고 생각해봐라)
- 유튜브나 인스타그램 같은 SNS 앱에서 추천 창에 뜬 이미지와 동영상 정보들. 메모리(이미 추천한 이미지가 미저리처럼 따라다닌다고?)
class MyClass { //생성자 선언 init() { print("My class 생성") } //소멸자 선언 deinit { print("My class 소멸") } } //인스턴스 생성(인스턴스가 메모리를 할당 받음) => myClass에 대한 Reference Count = 1 var myClass: MyClass? = MyClass() //myClass2가 myClass를 참조하게 된다. => Reference Count = 2 var myClass2 = myClass // Reference Count = 2-1 = 1 => Reference Count > 0 메모리에 살아 있음 myClass = nil // Reference Count = 1-1 = 0 => 메모리상에서 myClass가 사라져서 deinit이 호출된다. myClass2 = nil
class Jean { let mbti = "ENTP" init() { print("클래스 생성") } deinit { print("클래스 소멸") } } //옵셔널 타입의 Jean 인스턴스 생성 RC = 1 var jean: Jean? = Jean() //아무런 인자도 리턴값도 없는 클로저 생성, jean을 참조했기 때문에 RC = 2 let printMbti: () -> () = { [jean] in guard let jean else { return } //옵셔널을 해제해줄 guard let print("Jean's mbti = \(jean.mbti)") } printMbti() //메모리 할당 해제 -> printMbti에서 jean을 참조해서 남은 RC값이 1 남아 있어서 생성자 소멸 안 됨 jean = nil
// jean 참조시 weak를 넣어서 참조해야 한다. 아래 코드 참고. class Jean { let mbti = "ENTP" init() { print("클래스 생성") } deinit { print("클래스 소멸") } } //옵셔널 타입의 Jean 인스턴스 생성 RC = 1 var jean: Jean? = Jean() //아무런 인자도 리턴값도 없는 클로저 생성, jean을 참조했기 때문에 RC = 2 let printMbti: () -> () = { [ weak jean ] in guard let jean else { return } //옵셔널을 해제해줄 guard let print("Jean's mbti = \(jean.mbti)") } printMbti() //메모리 할당 해제 -> printMbti에서 jean을 참조해서 남은 RC값이 1 남아 있어서 생성자 소멸 안 됨 jean = nil
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 // lesson learned : 순환참조는 메모리 관리에 비효율적이기 때문에 피해야 한다. 순환참조가 발생하는 상황인지 점검할줄 알아야 한다.
'개발..................... > TIL' 카테고리의 다른 글
시뮬레이터 안 돌리고 빌드 컴파일 하는 방법 (0) 2024.07.23 테이블뷰 기본 (0) 2024.07.19 View Hierarchy 관련 오류 (0) 2024.06.30 #Preview macro, Xcode 코드베이스로 UI 설계할 때 유용한 팁 (0) 2024.06.27 Swift 코드베이스 준비하기(한 개의 페이지일 때) (0) 2024.06.24