iOS

[iOS] Memory Leak 방지하기.

Avante 2022. 5. 23. 21:55

앱 개발을 하다보면 Memory Leak이 심심찮게 발생하는경우가 있는데 이는 찾기도 힘들고 상황에 따라 재현하기도 어려워서

생각보다 속을 썩이는 경우가 많다.

오늘은 내가 실제 경험한 Leak들을 정리해보고 다음에 이런 케이스를 피하고자 정리해본다.

 

1. CollectionViewCell의 클로저에서 CollectionView 참조시 발생하는 Leak.

Cell에 클로저 동작을 추가하는 경우, 심심찮게 CollectionView를 리로드 하는 등 CollectionView를 참조할 일이 생기는데

이때 클로저내에서 바로 참조하면 Cell과 CollectionView가 서로 참조가 엮여 Cell이 메모리 해제되지않는 경우가 생긴다.

이를 해결하기 위해서 아래와같이 클로저 내에서 weak로 CollectionView를 접근하여 클로저 내에서 처리하면 Leak이 발생하지 않는다.

 

2. 클래스 외부에서 직접 내부변수에 Self로 접근하는 경우.

이런 경우는 대부분 Delegate를 구현할때 이렇게 하는데, 이때 Delegate를 받을 객체가 Weak로 선언되어 있지 않다면 Self를 넘겨준 클래스의 메모리가 해제 되지 않는다.

Self를 넘겨주는 클래스는 항상 내부에 Weak로 해당객체가 선언되어있는지 확인한다.

 

3. objc_setAssociatedObject등을 통해 Key를 정의하고, 이를 해제하지 않는 경우.

클래스를 확장하지 않고 변수등을 추가하고싶을때 objc_setAssociatedObject를 많이 쓰는편인데 이때 실수로 Key값을 정의한후

이를 해제하지 않아 Leak이 발생하는 경우가 있다.

objc_setAssociatedObject는 Self를 파라미터로 넘기기때문에 Self에 해당하는 클래스의 Reference Count가 1 증가하게 된다.

이를 기억하고 반드시 objc_setAssociatedObject를 사용한 클래스에서 Deinit시 해당 Key값 정의한것을 해제하도록 한다.

 

4. Timer 설정후 이를 Invalidate()처리하지 않는 경우.

Timer의 생성역시 Self를 타겟으로 넣기 때문에 Self의 Reference Count가 1 증가한다.

Timer를 소유한 클래스의 Deinit시 혹은 해당 Timer가 불필요해진 시점에 반드시 Invalidate()를 호출해주도록 한다.

 

5. Rx에서 내부 클로저로 Self를 참조하는 경우.

Rx를 통한 내부에서 다시 Closure로 Self를 참조할때 지나칠수 있는 문제.

Rx내부 다른 Closure로 Self를 참조한다고 생각하여 Rx에서 Weak Self처리를 해주지 않으면 Leak이 발생한다.

Rx의 Subscribe로 인한 Self참조시에는 반드시 Rx에서 Weak Self처리를 해주도록 한다.

 

6. 싱글턴 객체에 Strong으로 선언된 객체를 저장하고 해제하지 않는 경우.

보통 싱글턴이란 앱이 실행된후 Heap영역에 올라가고 앱이 메모리에서 해제되기 전까지 항상 상주해있는 객체이다.

해당 Leak이 발생하는 경우는 예를들어

A라는 View에서 싱글턴객체에 B라는 객체 10개를 저장한후(ex. 전역객체 저장 등) A가 사용자의 동작 등에 의해 내려가게 되면

B객체가 항상 메모리에 살아있게 된다.

이런경우 B로 인하여 Leak이 발생하기 때문에, 싱글턴 객체에 Struct 혹은 Class로 정의된 객체를 저장할시 적재적소에 해당 객체를 제거해주어 Leak을 피해야한다.