FishBun + Glide 앨범에서 이미지/비디오 로딩 중 메모리 폭증 트러블슈팅

매일 수정하는 GNOSS LV5·2025년 12월 24일

AndroidStudio

목록 보기
84/84

1) 현상

  • FishBun 앨범(RecyclerView + Grid 3분할)에서 스크롤하다가
    • 메모리가 순간 1GB까지 튐
  • 로그가 같이 발생
    • skia Error: Stream size exceeds the limit
    • Failed to create image decoder 'invalid input'
    • (비디오 쪽) setDataSource failed: status = 0x80000000

2) 핵심 원리 (왜 터지나)

이미지 메모리는 “파일 용량”이 아니라 “디코딩 결과 픽셀”이 결정

  • 예: TIFF/초고해상도 이미지
    • 저장 파일이 150MB여도 디코딩하면 내부 비트맵이 훨씬 커짐
  • 대략 메모리 사용:
    • ARGB_8888: 가로 × 세로 × 4byte
    • RGB_565: 가로 × 세로 × 2byte (절감 가능)

즉, 원본 해상도로 디코딩되는 순간 메모리가 폭발할 수 있음.

Glide에서 같은 .override(width, height)를 걸어도 JPG와 TIFF는 “언제, 어떻게” 크기 축소가 적용되는지가 달라서 메모리 폭증 여부가 갈린다. 핵심은 다운샘플링이 “디코드 단계에서” 일어나는지다.

2-1) 샘플링 / 다운샘플링이란?

  • 샘플링(sampling): 원본 픽셀을 전부 만들지 않고, 일정 간격으로 픽셀을 뽑아 더 작은 해상도의 이미지를 만드는 개념
  • 다운샘플링(downsampling): 샘플링 중에서도 “해상도를 줄이는 것”을 의미 (ex. 1/2, 1/4로 줄이기)

가장 중요한 포인트는 “언제 줄이느냐”다.

  • 디코드 단계 다운샘플: 압축 파일을 풀 때부터 작은 비트맵으로 생성 → 메모리 사용량이 처음부터 작음 (안 터짐)
  • 디코드 후 리사이즈: 일단 원본 해상도로 큰 비트맵을 만들고, 그 다음에 축소/크롭 → 피크 메모리가 원본 기준으로 한 번 튐 (터짐)

즉, override()는 “최종 결과”를 바꾸는 옵션처럼 보이지만, 디코더가 이를 디코딩 단계에 반영해주지 못하면 메모리 폭증을 막지 못한다.


2-2) override(width, height)가 실제로 하는 일

Glide의 override()는 단순히 “결과를 그 크기로 보여줘”가 아니라,

  1. 목표(target) 크기를 Glide에게 알려주고
  2. Glide가 디코더에게 requestedWidth/requestedHeight를 전달해서
  3. 가능하면 디코드 단계에서 다운샘플하게 만든다.

즉, 이상적인 경로는 아래다:

override로 target size 결정 → 디코더가 그 size에 맞춰 샘플링(inSampleSize 등) → 작은 비트맵 생성

이때 생성되는 비트맵 크기는 대략:

  • (요청 해상도) × bytesPerPixel
  • 예: 그리드 썸네일이 360×360이고 RGB_565면 360×360×2 ≈ 0.25MB 수준

반대로, override0이거나 디코더가 이를 무시하면:

target size를 못 잡음 → 샘플링이 적용되지 않음 → 원본 해상도(또는 매우 큰 크기)로 디코드 → 대형 비트맵 생성

이 순간 메모리 피크가 폭발한다.


3) Root Cause 정리

A. 문제 파일(특이 포맷) 유입

  • 실제로 문제 URI의 mimeType이 image/tiff
  • TIFF는 디코더/기기별 구현 차이/멀티페이지 등으로 디코딩이 무겁고 위험할 수 있음

B. override(target.width, target.height)가 0인 타이밍

  • RecyclerView bind 시점에 target.width/height == 0이 흔함
  • override 값이 0이면 Glide가 원하는 크기로 다운샘플하지 못하고
    • 원본 크기로 디코딩 시도 → 메모리 급증/OOM 가능
    • 혹은 TIFF파일은 Decorder가 tiff파일을 제대로 처리하지 못함.

4) “최소 수정” 방향 요약

이미지(그리드 썸네일)

  • target.width/height == 0 방어 → fallback px 사용
  • override(width, height)로 다운샘플 강제
  • DecodeFormat.PREFER_RGB_565로 썸네일 메모리 절감
  • 문제 포맷(TIFF 등) 제외 처리

6) 결론 (한 줄 요약)

이번 메모리 폭증은 (1) TIFF 같은 위험 포맷 유입 + (2) override 0 타이밍으로 원본 디코딩 발생 혹은 Glide의 tiff 디코더 미지원이 겹쳐서 생긴 이슈로 정리된다.

profile
러닝커브를 따라서 등반중입니다.

0개의 댓글