다른 언어에서는 주로 GC 사용
Garbage Collection
Garbage: 유효하지 않은 메모리
- C에서는
free()
함수로 직접 메모리 해제해야 함
- Java에서는 JVM의 garbage collector가 불필요한 메모리를 알아서 정리해줌
Minor & Major Garbage Collector
- 객체는 대부분 일회성되며, 메모리에 오랫동안 남아있는 경우는 드뭄
- 객체의 생존 기간에 따라 물리적 Heap 영역을 Young, Old으로 나뉨
- Young 영역, Young generation
- 새롭게 생성된 객체가 할당되는 영역
- 대부분의 객체가 금방 unreachable 상태가 되기 때문에 많은 객체가 Young 영역에 생성되었다가 사라짐
- Young 영역에 대한 garbage collection > Minor Collection
- Old 영역, Old Generation
- Young 영역에서 reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
- Young 영역보다 크게 할당됨
- 영역의 크기가 큰만큼 garbage는 적게 발생
- Old 영역에 대한 garbage collection > Major Garbage Collection
- Old 영역이 Young 영역보다 크게 할당되는 이유: Young 영역의 수명이 짧은 객체들은 큰 공간을 필요로 하지 않으며 큰 객체들은 Young 영역이 아니라 바로 Old 영역에 할당
Garbage Collection의 동작 방식
1. Stop The World: JVM이 애플리케이션의 실행을 멈추는 작업
- GC가 실행될 때는 GC를 실행하는 스레드를 제외한 모든 스레드들의 작업이 중단
2. Mark and Sweep
-
Mark: 사용되는 메모리와 사용되지 않는 메모리 식별 작업
-
Sweep: Mark 단계에서 사용되지 않음으로 식별된 메모리 해제 작업
-
Stop The World을 통해 모든 작업을 중단시키면 Garbage Collector는 스택의 모든 변수 또는 reachable 객체를 스캔하면서 각각이 어떤 객체를 참고하고 있는지를 탐색
-
Mark에서 사용 메모리 식별
-
Mark되지 않은 객체를 메모리에서 제거
Minor GC의 동작 방식
Young 영역은 1개의 Eden 영역과 2개의 Survivor 영역, 총 3가지로 나뉨
- Eden 영역: 새로 생성된 객체가 할당되는 영역
- Survivor 영역: 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
객체가 새롭게 생성되면 Young 영역의 Eden 영역에 할당됨
- Eden 영역이 꽉 차면 Minor GC 발생
- 사용되지 않는 메모리 해제
- Eden 영역에 존재하는 사용중인 객체는 Survivor 영역으로 이동
- Survivor 영역은 총 2개지만 반드시 1개의 영역에만 데이터가 존재해야 함
- 새로 생성된 객체가 Eden 영역에 할당됨
- 객체가 계속 생성되어 Eden 영역이 꽉 차게 되고 Minor GC가 실행됨
- Eden 영역에서 사용되지 않는 객체의 메모리가 해제
- Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동됨
- 1~2번의 과정이 반복되다가 Survivor 영역이 가득차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킴 > 1개의 Survivor 영역은 반드시 빈 상태가 됨
- 이러한 과정을 반복하여 계속해서 살아남은 객체는 Old 영역으로 이동(Promotion)됨
객체의 생존 횟수를 카운트하기 위해 Minor GC에서 객체가 살아남은 횟수를 의미하는 age를 Object Header에 기록
- Minor GC 때 Object Header에 기록된 age를 보고 Promotion 여부 결정
- Survivor 영역 중 1개만 반드시 사용되어야 함
- 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 현재 시스템이 정상 상황이 아님을 알 수 있음
Major GC 동작 방식
- Young 영역에서 오래 살아남은 객체는 Old 영역으로 Promotion됨
- Major GC: 객체들이 계속 promotion 되어 Old 영역의 메모리가 부족해짐
- Young 영역은 일반적으로 Old 영역보다 크기가 작기 때문에 GC가 보통 0.5초~1초 내에 끝남
- Minor GC는 애플리케이션에 큰 영향 주지 않음
- Old 영역은 Young 영역보다 큼 & Young 영역을 참조할 수 있음
- Major GC는 Minor GC보다 오래 걸리며 10배 이상의 시간 사용
Automatic Reference Counting
Automatic Reference Counting:
- Swift가 앱의 메모리 사용을 추적/관리 하는 방식
- 주로 프로그래머가 관리할 필요 없이 자동으로 더이상 필요없는 인스턴스가 사용하던 메모리를 해제함
- 오직 클래스 인스턴스만 관리
ARC 작동 방식
- 새로운 클래스 인스턴스를 생성할 때마다 ARC는 인스턴스 정보를 저장할 수 있도록 메모리 공간을 할당함
- 이 인스턴스 정보에는 인스턴스 종류와 저장된 값 등이 들어감
- 인스턴스가 더이상 필요 없어지면 다른 목적으로 쓰일 수 있도록 인스턴스에 할당된 메모리를 해제함: 쓸데없는 인스턴스가 메모리를 차지하지 않도록
- ARC가 사용 중인 인스턴스의 메모리를 해제하면 인스턴스의 속성과 메서드를 호출할 수 없게됨 > 앱의 비정상 종료 가능성 존재
- 인스턴스가 아직 필요할 동안 사라지지 않도록 ARC는 각 클래스 인스턴스를 참조하는 속성, 상수, 변수의 수를 추적함
- 현재 1개 이상의 참조가 존재하는 클래스 인스턴스는 해제되지 않음
- 클래스 인스턴스를 속성/상수/변수에 배정하면 이 속성/상수/변수가 인스턴스에 강한 참조(Strong reference)를 한다
- 참조하는 속성/상수/변수가 존재하는 동안에는 클래스 인스턴스가 해제될 수 없기 때문에 강하게 붙잡고 있는다 하여 강한 참조라 불림
Strong Reference Cycle
Strong Reference Cycle: 두 클래스 인스턴스가 서로에 대해 강한 참조일 때 각 인스턴스가 다른 인스턴스를 살아남게 함
Weak/unowned 참조를 통해 해결 가능: 순환 참조의 인스턴스가 강한 참조 없이 순환 내의 상대 인스턴스를 참조할 수 있도록
- Weak 참조:
- 상대 인스턴스가 더 짧은 수명을 가질 때 사용
- Unowned 참조:
Weak 참조
강한 참조가 아니기 때문에 ARC가 해제하는 것을 막지 못함
- weak 참조 중에 해제 가능 > 참조 중일 때 해제되면 런타임에 값을
nil
로 설정
속성/변수 선언 전에 weak
키워드 사용. 항상 값은 optional
Unowned 참조
속성/변수 선언 전에 unowned
키워드 사용
unowned 참조는 항상 값이 존재.
Unowned Optional 참조: Weak 참조와 같이 사용 가능
참고: