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메모리크래시

함께 읽기

로또 용지 QR 인식 성공이 0건이었던 이유: 기록하지 않은 경로는 실패처럼 보인다로또 앱 주간 보고에서 QR 화면을 연 사람은 19명인데 인식 성공은 0건이었습니다. 스캐너가 고장 난 게 아니라, 진짜 용지 QR 이 지나가는 경로에 기록이 하나도 없었습니다. 측정 구멍을 찾은 과정, 같은 기능 앱 4개와 비교한 결과, 스캔 엔진을 번들로 바꾼 이유, 고친 뒤 1주일 숫자를 정리합니다.지도 왼쪽 아래 로고를 누르면 앱이 꺼졌다: 네이버 지도 SDK 와 AppCompat 테마로또 판매점 지도 앱의 Crashlytics 에 「You need to use a Theme.AppCompat theme」 크래시가 4건 올라왔습니다. 사용자가 아니라 Play 사전 출시 보고서의 테스트 로봇이 지도 왼쪽 아래 NAVER 로고를 누른 것이었습니다. 원인, 앱 전체 테마를 바꾸지 않고 지도만 감싼 수정, 다크 모드에서 생긴 두 번째 문제를 정리합니다.광고 SDK 초기화가 끝나기 전에 광고를 요청하면 꺼진다: 막는 장치를 만들고도 세 번 다시 나온 이유운영 중인 앱에서 「MobileAds.initialize must be called」 크래시를 처음 고친 뒤에도 같은 크래시가 다른 모양으로 세 번 더 나왔습니다. 초기화 완료를 기다리는 장치는 있었지만, 시작 시점에 켜지는 값, 동의만 보고 켜지는 값, 그 장치를 거치지 않는 새 광고 자리가 빈틈이었습니다. 각 경우의 원인과 23개 앱 전수 점검 결과를 정리합니다.