Skip to content
isdnetworks
Go back

어떤 기기에서만 죽었다

앱이 어떤 기기에서만 죽었고 언제 죽는지도 일정하지 않았다.

Table of contents

Open Table of contents

주소만 나왔다

죽을 때 logcat 을 봤는데 신호 번호와 주소만 있었다.

Fatal signal 11 (SIGSEGV)
#00 pc 0001a2b4  libgame.so

자바에서 죽으면 어느 줄인지 나오는데 네이티브 쪽은 주소뿐이다. 어디서 죽었는지를 알 방법이 로그에 없었다.

디버그 정보를 따로 보관했다

찾아보니 ndk-stack 이 있었다. logcat 을 그대로 물려 주면 주소를 함수와 줄 번호로 바꿔 준다.

$ adb logcat | ndk-stack -sym obj/local/armeabi

-sym 이 가리키는 것은 심볼이 안 지워진 쪽이다. 앱에 담기는 libs/armeabi/ 는 지워져 있고 obj/local/armeabi/ 에 원본이 남는다. 그런데 그 폴더는 다음 빌드가 덮는다. 그래서 배포한 판마다 그것을 따로 보관하게 했다. 같은 빌드여야 주소가 맞으므로 어느 판에서 죽었는지를 알아야 맞는 것을 꺼낸다.

예외를 안 보고 있었다

이렇게 해서 죽는 자리를 찾으니 자바를 부르는 부분이었다. 부르고 나서 ExceptionCheck() 를 안 하고 있었다.

자바 쪽에서 예외가 나면 그 상태가 JNIEnv 에 남는다. 그 상태로 다음 호출을 하면 죽는다. 확인하고 ExceptionClear() 로 지우는 것을 넣었다. 확인만 하고 안 지우면 여전히 남아 다음 호출에서 또 죽는다.

왜 예외가 났는지도 봤다. 전달한 값이 유효 범위를 벗어났는데 기기마다 화면 크기나 설정이 달라 어떤 기기에서만 범위 밖이 됐다. 넘기기 전에 값을 검사하는 것도 넣었다.

두 곳에서 막은 셈이다. 값 검사만 하면 다른 이유로 나는 예외를 못 잡는다. 예외 확인만 하면 예외가 나긴 난다. 둘 다 필요했다.

참조의 짝

같은 부분에서 다른 것도 나왔다. 자바 객체를 나중에 쓰려고 오래 들고 있었는데 넘어온 참조는 그 호출 동안만 유효하다.

jobject global = env->NewGlobalRef(obj);
// 다 쓰면
env->DeleteGlobalRef(global);

오래 들고 있으려면 NewGlobalRef 로 바꾸고 다 쓰면 DeleteGlobalRef 로 놓아야 한다. 여기서도 얻으면 놓는 짝이었다. 경계를 넘는 것은 대개 짝이 있었다.

정리


Share this post on:

Previous Post
중계하면서 다듬었더니 안 맞았다
Next Post
같은 자원인데 경로마다 규칙이 달랐다