Xcode Instruments로 메모리 누수 점검은 몇번 해봤지만 다른 템플릿의 Instrument를 사용해본 적이 없어 여기저기 확인해봤는데 템플릿들에 대해 정리한 내용이 공식문서에도 없어 각 템플릿의 목적과 Instrument에 대해서 정리했습니다.
Apple에서 Hang을 감지하는 방법과 원인을 파악해 수정하는 튜토리얼을 제공해 따라했습니다.
기존에 Hang을 Sentry에서 감지될 때 Crash가 발생할 때 같이 감지되서 Crash로 인한 Hang인지 정말 Hang만 발생한 건지 원인에 대해 파악하기 어려웠는 데 Instruments의 Time Profiler 템플릿을 사용해서 분석하게 되니까 설정한 시간을 초과하면 바로 알려줘서 파악하기 쉬웠습니다.
각 템플릿들의 목적에 맞게 개발한 앱들을 전체 점검해보았는데 서비스 향상에 도움이 될 것 같았습니다.
성능을 검사할 때 추가로 Firebase Performance Monitoring 을 사용할 수 있는 데 Remote Config가 의존성을 가져 자동으로 설치되어 필요할 때 마다 비활성화를 할 수 있어서 크게 서비스 중인 앱에도 영향도가 적고 성능 정보를 얻고 싶을 때 유용할 것 같습니다.
메모리 누수점검을 진행하면서 다시 한번 iOS 메모리 개념도 정리했습니다.
관련 WWDC를 시청했습니다.
메모리 관리를 잘해야 앱 실행 속도시스템 , 전체 성능 향상, 직접 만든 앱 외에 다른 앱들도 메모리에 오래 머물 수 있습니다.
Swift의 깊은 복사, 얕은 복사, COW
참고로 얕은 복사하는 참조타입을 깊은 복사가 가능하도록 NSCopying 프로토콜을 사용합니다.
Xcode Instruments나 라이브러리 사용 하기 전에 항상 인지하도록 메모리 누수가 자주 발생하는 케이스를 정리했습니다
함수형프로그래밍 강의를 들으면서 과제 중 ImageLoader를 함수형으로 구현하기가 있었는 데 해당 객체를 만들면서 E-Tag와 다운샘플링도 적용된 ImageLoader 패키지를 만들면 여러 프로젝트에서 사용하기 편리할 것 같아 개발을 시작했습니다.
E-Tag, 메모리캐시, 디스크 캐시, 다운샘플링 등의 개념을 정리했습니다.
메모리캐시는 NSCache를 사용, 디스크 캐시는 FileManager를 사용했습니다.
Result+Extension을 통해 실패할 때 와 성공했을 때 플로우를 하나의 파이프라인에서 각각 실행시킬 수 있습니다.
여러 블로그에서 개인 ImageLoader를 다양하게 구현한 글들이 많았고 NSCache 대신에 직접 Swift용으로 구현한 분도 인상적이였습니다.
아래 플로우차트로 동작방식을 확인할 수 있고 my-swift-package에서 활용할 예정입니다.
graph TD
A("이미지 로드 요청") --> B("캐시 키(Key) 생성
URL + 다운샘플링 옵션 조합");
B --> C{메모리 캐시 확인};
C -- Hit --> D{ETag 검증 네트워크};
C -- Miss --> E{디스크 캐시 확인};
D -- "✅ 304 (유효)" --> F([메모리 캐시 데이터 사용]);
D -- "🔄 200 (변경됨)" --> J[새로운 데이터 처리];
E -- Hit --> D{ETag 검증};
E -- Miss --> H[네트워크 요청];
D -- "✅ 304 (유효)" --> I([디스크 캐시 데이터 사용]);
I --> I_Save(메모리에 저장);
H --> J;
subgraph " "
J --> K(메모리에 저장);
K --> L(디스크에 저장);
end
F --> Z_Pre(최종 데이터 확정);
I_Save --> Z_Pre;
L --> Z_Pre;
Z_Pre -- "다운샘플링 옵션 O" --> Z_Downsample(다운샘플링 수행);
Z_Pre -- "다운샘플링 옵션 X" --> Z_Final(UIImage 반환);
Z_Downsample --> Z_Final;
style A fill:#B3E5FC,stroke:#333,stroke-width:2px
style J fill:#FFF9C4,stroke:#333,stroke-width:2px
style H fill:#FFCDD2,stroke:#333,stroke-width:2px
style Z_Final fill:#C8E6C9,stroke:#333,stroke-width:2px