- Fundamental
- 크래시?: 허용되지 않은 작업을 했을 때, 앱이 종료되는 것
- CPU가 해당 코드를 실행하지 못할 때
- OS가 강제하는 정책을 위반했을 때
- 프로그래밍 언어가 잘못된 동작을 감지했을 때(배열 범위 넘어가는 접근이라던지)
- 개발자가 스스로 걸어놓은 단정문에서 오류가 감지되었을 때
- 크래시는 어떻게 보이는가?
- 크래시가 난 지점에서 멈춰서, 그 상태의 stack trace를 보여준다.
- 디버거가 없는 상황에서는, 이 로그가 디스크에 저장된다.
- 심볼이 없는 상태에서 저장되지만, Xcode는 이걸 바꿀 수 있다 -> dSYM을 가지고
- Xcode Organizer에 testFlight와 AppStore 앱들의 크래시 로그를 볼 수 있다.
- 모든 플랫폼과 익스텐션에 대해서 제공
- 최근 통계, 가장 영향을 많이 받는 디바이스, 페이지 단위 로그 확, 프로젝트에서 디버그 확인, 하이라이팅 등…
- 이슈가 해결 됐는지 여부도 체크할 수 있다.
- 지원하기 위해서는?
- 앱스토어 사용자가 동의해야 한다
- Xcode에 sign-in해야 한다.
- 앱을 심볼과 함께 업로드 해야 한다.
- 이후에는 Organizer의 crash 탭을 확인하면 된다.
- 크래시 로그를 보는 방법
- Organizer
- Devices Window
- 테스트 런
- 콘솔
- 디바이스에서 공유하기
- 심볼화 best-simulation
- 앱 심볼을 함께 업로드하기
- 앱 아카이브 유지하기-로컬 심볼화를 위해
- bitcode가 포함된 경우는, symbol을 다운로드 해줘야 한다 -> 디바이스마다 다시 만들어주기 때문인 듯?
- 크래시 로그 분석하기
- 구조: 요약 - 크래시 원인 - 크래시 메시지 - 스택 트레이스(1개 이상) - 레지스터 상태 - 로딩된 바이너리
- 크래시 로그가 발생하는 경우
- Assertion과 Preconditions
- 에러가 발생했을 때, 의도적으로 프로세스를 중단하기 위한 장치
- nil을 강제 언래핑
- Array의 범위 바깥 접근
- 산술 오버 플로우
- 캐치되지 않은 예외
- 사용자 지정 assertion
- OS에 의한 종료
- watchdog 이벤트
- 디바이스 과열
- 메모리 고갈
- 유효하지 않은 코드 시그니
- 이런 종류의 크래시 로그는 Device Window에서 확인 가능
- 주요 크래시 원인
- 런치 타임 제한 초과
- 시뮬레이터와 디버거가 붙은 경우에는 재현되지 않으니 실기기에서 디버거 끄고 테스트할 것
- 오래된 하드웨어도 반드시 테스트 할 것
- 메모리 에러
- 메모리 할당 전 접근, 해제 후 접근, 버퍼 오버 플로우
- 읽기 전용 메모리에 쓰기를 시도하거나, 존재하지 않는(할당 받지 않은) 메모리 접근할 경우
- 해제된 객체의 경우, isa가 4bit만큼 왼쪽으로 시프트되어 있다. -> 이미 해제된 객체임을 알리기 위해서
- 어떤 객체가 release됐는지 확인하려면 어떻게 해야 할까?
- release메소드는 컴파일러가 만드는 메소드라, 사용자가 인지할 수 없다.
- 뒤에 붙어있는 offset을 이용해서, disassemble해서 역으로 추적할 수 있다.
- 자주 발생하는 메모리 에러
- objc_msgSend 혹은 retain/release
- Unrecognized selector exception
- malloc/free할 때의 abort()
- crash 분석 팁
- 크래시가 난 라인보다는 코드를 분석하라 -> 넓게 보라
- 크래시 난 스레드 말고도 다른 스레드를 보라
- 여러개의 크래시 로그를 보라
- 메모리 에러를 발생시키기 위해서는 Address Sanitizer와 zombies를 사용하자.
- 멀티 스레딩 이슈
- 재현하기 어려운 이슈
- 해당 버그는 대부분 메모리 오염을 발생시킨다.
- 여러 스레드가 연관되어 있다.
- 크래시 원인과 발생 지점이 다른 경우가 많다.
- Thread Sanitizer
- 확정적으로 스레드 이슈를 확인 가능
- 시뮬레이터에서만 동작
- 실제로 동작하는 코드에서만 체크 가능