기어가더라도 제대로

PHPickerController와 효율적 메모리 사용(feat. memory leak) 본문

만난 에러들

PHPickerController와 효율적 메모리 사용(feat. memory leak)

Damagucci-juice 2022. 8. 17. 14:12

사건 개요

PHPickerViewController 를 사용할 때, 엄청난 메모리 압박에 시달렸다.

  • 15장 사진 업로드 비교

기존 방식 - 낭낭하게 713MB 사용중이시다.
Pixel scale을 조정한 방식 - 39.1MB를 사용한다.

사용법

엄청 큰 UIImage의 메모리 사용량

UIImage 자체의 크기가 매우 커서 변화를 줘야했다.

  • 기존
    • result → UIImage → pngData → UIImage
  • 변경
    • result → URL (→ cgImage → Data) → UIImage
      • 괄호 안은 보이지 않고, 내부적으로 동작하는 부분

결론적으로 UIImage 의 크기가 엄청 커서 이를 작게 설정하는 것이 중요하다.

픽셀(사진 화질)의 규모를 원본보다 작게 설정하는 것이 핵심이다.

UIImage를 이용할 때 들어가는 메모리의 양은 실제 사진 이미지 파일의 크기가 아니다.

실제 이미지 파일을 불러와 r,g,b,alpha 값을 구성해야하기 때문에 다음과 같은 공식이 만들어 진다.

Memory size of a image = (image size * 4) * pixel scale

이미지를 4개 겹친 상태에서 pixel 규모 크기 만큼 곱한다. 그래서 pixel scale 을 줄이는 전략으로 접근하였다.

구현 해보죠

url extension 부분이 복잡하게 느껴진다.

하나하나씩 부셔봅시다

(부셔지는 건 나였고)

  • 1. URL로 작은 크기의 CGImage를 만들고,
  • 2. CGImage를 Data로, 만든 Data를 UIImage로 만드는 코드입니다.

  • 보다 작은 크기의 CGImage를 만드는 코드
    • maxDimensionsInPixel 변수를 눈여겨 보시면 크기를 픽셀 스케일을 조절하는 부분이라는 것을 알 수 있습니다.
let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary

// URL -> CgImageSource
guard let source = CGImageSourceCreateWithURL(self as CFURL, sourceOptions) else { return nil }

// Screen size
let scale: CGFloat = UIScreen.main.scale

// Pixel scale fitted to PhotoView
/// 이건 지금 프로젝트 환경에 맞추기 위해 적은 코드
/// PhotoView의 가장 긴 변을 기준으로 scale 과 곱해서 변수에 저장
let maxDimensionsInPixel = max(ShapeSize.height, ShapeSize.width) * scale

// Downsampling options
let downsampleOptions = [
    kCGImageSourceCreateThumbnailFromImageAlways: true,
    kCGImageSourceCreateThumbnailWithTransform: true,
    kCGImageSourceThumbnailMaxPixelSize: maxDimensionsInPixel,
] as CFDictionary

guard let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, downsampleOptions) else { return nil }
  • CGImage 를 바탕으로 Data를 만들어 UIImage를 리턴하는 코드
    • CGImgae → Data 로 갈 때 어떤 처리가 이뤄집니다.
    • cgImage가 png인지 아닌지에 따라 압축률이 달라지는 코드입니다.
    • 어떤 게시물에서는 CGImageDestinationCreateWithData 의 두번째 매개변수에서 kUTTypeJPEG 라고 사용하는데 이는 deprecated 된 코드입니다. 아래대로 써야 해요.
// Convert cgImage to Data
let data = NSMutableData()
guard let imageDestination = CGImageDestinationCreateWithData(data, UTType.jpeg.identifier as CFString, 1, nil) else { return nil }

let destinationProperties = [kCGImageDestinationLossyCompressionQuality: cgImage.isPNG ? 1.0 : 0.75] as CFDictionary
CGImageDestinationAddImage(imageDestination, cgImage, destinationProperties)
CGImageDestinationFinalize(imageDestination)

return UIImage(data: data as Data)

전체 코드

UIImage 초기화 방식에 따른 메모리 차이

  • UIImagenamed 방식으로 생성하는지, imageWithContentsOfFile 방식으로
    생성하는지에 따라 메모리 사용량에서 차이가 크다고 한다.
    • named
      • 적은 수의 이미지를 자주 사용할 때 적합
    • imageWithContentsOfFile
      • 많은 수의 이미지를 다룰 때 적합 (콜렉션뷰 마다 이미지뷰)

출처

Extreamly memory usage when picker image from UIImagePickerViewController?

 

Extreamly memory usage when picker image from UIImagePickerViewController?

I have implement function for upload image but before upload I will preview image to user. func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) But suddenly I

stackoverflow.com

Using PHPickerViewController Images in a Memory-Efficient Way

 

Using PHPickerViewController Images in a Memory-Efficient Way

Using PHPickerViewController Images in a Memory-Efficient Way PHPickerViewController is (in my opinion) one of the more exciting parts of iOS 14. We developers now have a fully-fledged photo picker that we can just use, rather than having to spend a bunch

christianselig.com

https://developer.apple.com/forums/thread/684101

 

valid replacement for kUTTypeJPEG … | Apple Developer Forums

So, I had a similar circular warning for this same method where I wanted to identify a JPG or a PNG image and create an image with the appropriate extension. Although a good example of how to use it was not clear to me and here's what worked for me (Object

developer.apple.com

 

https://wanpakaworld.tistory.com/entry/Xcode-Objective-C-Swift-UIImage-imageNamed-%EB%A9%94%EC%86%8C%EB%93%9C-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EB%B0%98%EB%93%9C%EC%8B%9C-%EC%A3%BC%EC%9D%98%ED%95%B4%EC%95%BC-%ED%95%A0-%EC%A0%90

 

[Xcode, Objective-C, Swift] UIImage imageNamed 메소드 사용시 반드시 주의해야 할 점

최근 담당하고 있는 제품의 iOS에서 속도관련 이슈가 문제시 됐다. 담당 제품의 특성상 생성시점에 불러오는 작은 이미지 리소스가 수백개가 넘는데, 이때 속도 이슈가 발생했다. 모바일 어플리

wanpakaworld.tistory.com

 

https://swiftsenpai.com/development/reduce-uiimage-memory-footprint/

 

Reducing Memory Footprint When Using UIImage - Swift Senpai

Learn how to use image downsampling to drastically reduce an app memory footprint when dealing with high definition UIImage.

swiftsenpai.com

 

Comments