EEltaCrew
홈 › 블로그

이미지 줄여 읽기 한 줄이 만든 크래시: inSampleSize 는 0 에서 시작한다

게시 2026-10-13실측 기준 2026-10-13읽는 시간 약 4분elta · EltaCrew

메모리를 아끼려고 QR 스캐너 앱 문서함의 썸네일을 줄여 읽게 바꿨더니, 다음 버전에서 문서 목록을 열 때마다 앱이 꺼졌습니다. 원인은 BitmapFactory.Options 의 inSampleSize 기본값이 0 이라는 것이었습니다. 바꾼 코드, 크래시 기록, 고친 코드, 같은 실수를 다른 곳에서 찾은 방법을 정리합니다.

메모리 권장 사항에서 시작했다

10월 10일, Play Console 의 메모리 관련 권장 사항을 보고 운영 중인 앱에서 이미지를 원본 크기 그대로 디코딩하는 곳을 찾아 고쳤습니다. QR 스캐너 앱의 문서함 목록이 그중 하나였습니다.

문서함 목록의 한 칸에는 작은 썸네일이 있습니다. 그런데 그 썸네일 파일은 스캔한 페이지의 원본 JPEG 이었습니다. 작은 칸 하나를 그리려고 원본 해상도 이미지를 통째로 메모리에 올리고 있었던 겁니다.

바꾼 코드

먼저 크기만 읽고, 짧은 변이 320px 아래로 내려가지 않는 선까지 2배씩 줄여서 읽도록 바꿨습니다.

BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, bounds);

BitmapFactory.Options opts = new BitmapFactory.Options();
int minDim = Math.min(bounds.outWidth, bounds.outHeight);
while (minDim / (opts.inSampleSize * 2) >= 320) opts.inSampleSize *= 2;
Bitmap bmp = BitmapFactory.decodeFile(path, opts);

빌드는 통과했고, 이 변경은 다른 수정들과 함께 10월 11일 1.1.25 로 나갔습니다.

문서 목록을 열면 매번 꺼졌다

다음 날 Crashlytics 에 새 크래시가 올라왔습니다.

java.lang.ArithmeticException: divide by zero
    at ...ui.document.DocumentAdapter.lambda$onBindViewHolder$1

10월 13일 오전 9시까지 7일 동안 27건, 사용자 4명이었고 전부 1.1.25 였습니다. 썸네일이 있는 문서가 하나라도 있으면 문서함을 여는 순간 앱이 꺼지는 상태였습니다. 썸네일 디코딩은 백그라운드 스레드에서 돌기 때문에, 거기서 난 예외를 잡는 곳이 없어 앱 전체가 종료됐습니다.

원인: 기본값이 0 이다

new BitmapFactory.Options() 로 만든 옵션의 inSampleSize 는 0 입니다. 디코더는 1 이하의 값을 1 로 취급하기 때문에 디코딩만 할 때는 0 이어도 문제가 없습니다. 그래서 평소에는 이 값이 0 이라는 걸 의식할 일이 없습니다.

문제는 그 값을 계산에 바로 썼다는 점입니다. 반복문의 첫 계산이 minDim / (0 * 2), 곧 minDim / 0 이 됩니다.

Android 문서의 예제는 계산을 지역 변수 int inSampleSize = 1; 로 시작합니다. 우리 코드는 옵션 객체의 필드를 반복문 변수로 바로 쓰면서 1 로 시작하는 줄을 빠뜨렸습니다.

테스트에서 걸러지지 않은 이유도 분명합니다. 「화면은 같고 내부만 바뀌는」 수정이라 빌드가 통과한 것만 보고, 썸네일이 있는 문서 목록을 실제로 열어 보지 않은 채 내보냈습니다.

고친 것

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 1;
int minDim = Math.min(bounds.outWidth, bounds.outHeight);
while (minDim > 0 && minDim / (opts.inSampleSize * 2) >= 320) opts.inSampleSize *= 2;

10월 13일 1.1.26 으로 제출했고, 이번에는 제출할 출시 빌드를 실기기에 깔아 갤러리 사진으로 문서를 만들고 문서함 목록에서 썸네일이 뜨는 것까지 확인했습니다.

같은 실수가 다른 곳에도 있나

줄여 읽기 코드는 다른 앱에도 있어서, inSampleSize * 2 로 운영 중인 앱 코드 전체를 검색했습니다.

문제가 된 곳은 하나였습니다.

정리

이 글의 앱은 QR코드리더: 바코드 스캐너(Google Play) 입니다.

AndroidBitmapFactoryCrashlytics메모리크래시

함께 읽기

Crashlytics 에 안 잡힌 크래시: 넣은 버전부터만 보인다앱 21개에 Firebase Crashlytics 를 넣고 사흘 뒤, 사용자가 겪은 크래시를 Play Console 에서 먼저 발견했습니다. Crashlytics 는 SDK 를 넣은 빌드부터만 보고하고, 사용자 폰에 남아 있는 옛 버전의 크래시는 Play vitals 에만 쌓입니다. 21앱 전수 결과와 지금 쓰는 확인 순서를 정리합니다.동기화가 판매점 8,802곳을 지운 날: 공공데이터 필드 이름 하나와 100건짜리 목록로또 판매점 지도 앱에서 동기화 뒤 판매점 이름이 전부 「알수없음」으로 바뀌고, 앱에 넣어 둔 판매점 8,802곳이 사라졌습니다. 공공데이터 응답의 필드 이름 변경, 첫 100건만 받은 목록으로 삭제하던 동기화, 지오코더의 없는 키까지 원인 세 가지와 고친 방법을 정리합니다.TV 페어링 코드 창에서 사용자가 떠난 이유: 6자리 코드와 한글 자판TV 리모컨 앱의 페어링 오류를 고친 뒤 오히려 「코드 입력 창에서 취소」가 9% 에서 19% 로 늘었습니다. GA4 실패 사유를 열어 보고, 코드 입력칸 하나가 한글 자판으로 열리던 것을 찾은 과정과 고친 방법을 정리합니다.