아 리 데이터 iOS 단 시작 속도 최적화 심득

배경
7 월 26 일 에 우리 알 리 데이터 iOS 에서 4.4.0 버 전 을 발 표 했 는데 이번 버 전 은 주로 성능 을 최적화 시 켰 다.그 중에서 main()단계 의 시작 시간 최적화 성과 가 비교적 뚜렷 하 다.이전의 0.5-0.7 초 에서 현재 의 0.1-0.2 초(main()첫 번 째 줄 코드 에서 didFinishLaunching With Options 마지막 줄 코드 까지 의 시간 소모)로 낮 아 지면 서 사용자 체험 이 뚜렷하게 향상 되 었 다.여기 서 최 적 화 된 경험 을 정리 하고 여러분 이 함께 교류 하 는 것 을 환영 합 니 다.
응용 시작 프로 세 스
iOS 응용 프로그램의 시작 은 pre-main 단계 와 main()단계 로 나 눌 수 있 는데 그 중에서 시스템 이 하 는 일 은 다음 과 같다.
1.pre-main 단계
1.1.실행 가능 한 파일 불 러 오기
1.2.동적 링크 라 이브 러 리 로 더 dyld(dynamic loader)불 러 오기
1.3.dyld 재 귀적 으로 모든 의존 하 는 dylib(dynamic library 동적 링크 라 이브 러 리)를 불 러 옵 니 다.
2.main()단계
2.1.dyld 호출 main()
2.2.UIApplicationMain()호출
2.3.applicationWillFinishLauncheng 호출
2.4.didFinishLaunchingWithOptions 호출
시간 측정 시작
최적화 하기 전에 우 리 는 먼저 각 단계 의 시간 소 모 를 측정 할 수 있어 야 한다.
1.pre-main 단계
pre-main 단계 에 대해 애플 은 Xcode 에서 scheme->Run->Auguments 에서 환경 변 수 를 DYLD 편집 하 는 측정 방법 을 제공 합 니 다.PRINT_STATISTICS 를 1 로 설정:

pre-main 단계 시작 시간 측정.png
설정 후 프로그램 을 실행 하면 콘 솔 에 다음 과 같은 출력 이 있 습 니 다.pre-main 단계 의 각 과정 이 한눈 에 들 어 옵 니 다.(Apple 이라는 Demo 는 너무 과장 되 었 습 니 다.)

pre-main 단계 시작 시간 측정.png
2.main()단계
main()단계 에 대해 서 는 main()함수 가 didFinishLaunching WithOptions 실행 이 끝 날 때 까지 실 행 될 시간 을 측정 하 는 것 입 니 다.프로젝트 에 코드 를 삽입 해 야 합 니 다.main()함수 에서 현재 시간 을 변수 StartTime 으로 기록 합 니 다.

CFAbsoluteTime StartTime;
int main(int argc, char * argv[]) {
   StartTime = CFAbsoluteTimeGetCurrent();
AppDelegate.m 파일 에서 전역 변수 StartTime 을 extern 으로 설명 합 니 다.

extern CFAbsoluteTime StartTime;
마지막 으로 didFinishLaunching With Options 에서 현재 시간 을 다시 가 져 옵 니 다.StartTime 과 의 차 이 는 main()단계 의 운행 시간 입 니 다.

double launchTime = (CFAbsoluteTimeGetCurrent() - StartTime);
pre-main 단계 최적화
pre-main 단계 의 시간 소 모 를 최적화 하려 면 Dld 로 딩 하 는 과정 을 다시 배 워 야 합 니 다.Apple 의 WWDC 에 따 르 면 Dld 로 딩 은 주로 4 단계 로 나 뉜 다.
1. Load dylibs
이 단계 에서 dyld 는 응용 에 의존 하 는 dylib 를 분석 하고 mach-o 파일 을 찾 아 이 파일 들 을 열 고 읽 으 며 유효성 을 검증 합 니 다.이 어 코드 서명 을 찾 아 커 널 에 등록 하고 마지막 으로 dylib 의 모든 segment 에 mmap()를 호출 합 니 다.
일반적인 상황 에서 iOS 응용 프로그램 은 100-400 개의 dylibs 를 불 러 옵 니 다.그 중에서 대부분 은 시스템 라 이브 러 리 입 니 다.이 부분 dylib 의 로드 시스템 은 최적화 되 었 습 니 다.
그래서 의존 하 는 dylib 는 적 을 수록 좋다.이 단계 에서 우리 가 할 수 있 는 최 적 화 는 다음 과 같다.
가능 한 한 내장(embedded)의 dylib 를 사용 하지 않 고 내장 dylib 를 불 러 오 는 성능 비용 이 많이 듭 니 다.
기 존 dylib 와 정적 라 이브 러 리(static archives)를 통합 하여 dylib 의 사용 개 수 를 줄 입 니 다.
dylib 를 게 으 르 게 불 러 오지 만 dlopen()에 문제 가 생 길 수 있 으 며,실제로 게 으 르 게 불 러 오 는 작업 이 더 많 을 수 있 습 니 다.
2. Rebase/Bind
dylib 의 로드 과정 에서 시스템 은 안전 을 위해 ASLR(Address Space Layout Randomization)기술 과 코드 서명 을 도입 했다.ASLR 의 존재 로 인해 미 러(Image,실행 가능 한 파일,dylib,bundle 포함)는 무 작위 주소 와 이전 포인터 가 가리 키 는 주소(preferredaddress)에 편차(slide)가 있 을 수 있 습 니 다.dyld 는 이 편 차 를 수정 하여 정확 한 주 소 를 가리 키 도록 해 야 합 니 다.
Rebase 는 앞 에 있 고,Bind 는 뒤에 있 으 며,Rebase 는 미 러 를 메모리 에 읽 고,미 러 내부 의 지침 을 수정 하 며,성능 소 모 는 주로 IO 에 있다.Bind 는 조회 기호 표를 만 들 고 미 러 외 부 를 가리 키 는 지침 을 설정 하 며 성능 소 모 는 주로 CPU 에서 계산 합 니 다.
그래서 지침 수량 이 적 을 수록 좋다.이 단계 에서 우리 가 할 수 있 는 최 적 화 는 다음 과 같다.
ObjC 클래스(class),방법(selector),분류(category)의 수량 감소
C++가상 함수 의 수 를 줄 입 니 다.(가상 함 수 를 만 드 는 데 비용 이 듭 니 다)
Swift structs 사용 하기(내부 최적화,기호 수량 이 더 적 음)
3. Objc setup
대부분의 ObjC 초기 화 작업 은 Rebase/Bind 단계 에서 완료 되 었 습 니 다.이 단계 에서 dyld 는 모든 설명 한 ObjC 클래스 를 등록 하고 클래스 의 방법 목록 에 분류 하여 각 selector 의 유일 성 을 검사 합 니 다.
이 단계 에서 최적화 할 만 한 것 이 별로 없다.Rebase/Bind 단계 가 최적화 되면 이 단계 의 소모 시간 도 줄 어 들 것 이다.
4. Initializers
이 단계 에 이 르 러 dyld 는 프로그램의 초기 화 함 수 를 실행 하기 시 작 했 습 니 다.각 Objc 클래스 와 분류의+load 방법 을 호출 하고 C/C++의 구조 기 함수(attribute(constructor)로 수식 하 는 함수)를 호출 하 며 기본 형식 이 아 닌 C+정적 전역 변 수 를 만 듭 니 다.Initializers 단계 가 실 행 된 후,dyld 는 main()함 수 를 호출 하기 시작 합 니 다.
이 단계 에서 우리 가 할 수 있 는 최 적 화 는 다음 과 같다.
클래스+load 방법 에서 일 을 적 게 하고,가능 한 한+initiailize 로 미 루 십시오.
구조 기 함수 개 수 를 줄 이 고 구조 기 함수 에서 일 을 적 게 합 니 다.
C++정적 전역 변수의 개 수 를 줄 입 니 다.
main()단계 최적화
이 단계 의 최 적 화 는 주로 didFinishLaunching WithOptions 방법 에서 의 작업 을 줄 이 는 것 입 니 다.didFinishLaunching WithOptions 방법 에서 저 희 는 응용 window 를 만 들 고 rootView Controller 를 지정 하여 window 의 MakeKey AndVisible 방법 을 사용 하여 보 여 줍 니 다.업무 수요 로 인해 저 희 는 각 2 자/3 자 라 이브 러 리 를 초기 화하 고 시스템 UI 스타일 을 설정 하여 안내 페이지 를 표시 할 필요 가 있 는 지,로그 인 할 필요 가 있 는 지,새로운 버 전이 있 는 지 등 을 검사 할 것 입 니 다.역사적 인 이유 로 이곳 의 코드 는 비교적 커지 기 쉬 우 며 시작 시간 을 통제 하기 어렵 습 니 다.
따라서 업무 수 요 를 만족 시 키 는 전제 에서 didFinishLaunching With Options 는 메 인 스 레 드 에서 하 는 일이 적 을 수록 좋 습 니 다.이 단계 에서 우리 가 할 수 있 는 최 적 화 는 다음 과 같다.
각 2 자/3 자 라 이브 러 리 를 정리 하고 로드 지연 이 가능 한 라 이브 러 리 를 찾 아 로드 지연 처 리 를 합 니 다.예 를 들 어 첫 페이지 컨트롤 러 의 view Did Appear 방법 에 넣 습 니 다.
업무 논 리 를 정리 하고 집행 을 지연 시 킬 수 있 는 논 리 를 지연 시 켜 집행 처 리 를 한다.예 를 들 어 새 버 전 검사,등록 푸 시 알림 등 논리.
복잡 한 계산 을 피하 다.
홈 페이지 컨트롤 러 의 viewdLoad 와 viewWillAppear 에서 너무 많은 일 을 하지 않도록 합 니 다.이 두 가지 방법 이 실행 되 어야 홈 페이지 컨트롤 러 가 표시 되 며,일부 생 성 을 지연 시 킬 수 있 는 보 기 는 생 성/게 으 름 로드 처 리 를 해 야 합 니 다.
성능 이 더 좋 은 API 를 사용 합 니 다.
홈 페이지 컨트롤 러 는 순수 코드 방식 으로 구축 된다.
아 리 데이터 iOS 엔 드 최적화 실천
이상 의 인지 지도 아래 알 리 데이터 iOS 단 은 최적화 에 착 수 했 고 pre-main 단계 와 main()단계 에서 각각 일련의 최적화 를 하여 어느 정도 성 과 를 거 두 었 다.
1.pre-main 단계 의 최적화
1.1.쓸모없는 dylib 를 검사 하고 더 이상 사용 하지 않 는 libicucore.tbd 를 제거 합 니 다.
1.2.쓸모없는 파일&라 이브 러 리 를 삭제 하고 중복 파일(여러 중복 분류)을 합 친다.더 이상 사용 하지 않 는 라 이브 러 리 UMSocial,PSTCollection View,MCSwipeTableView Cell 을 제거 하고 기능 이 중복 되 는 라 이브 러 리 Mantle 을 제거 합 니 다.
1.3.각 유형의+load 방법 을 정리 하고 여러 가지 유형 중+load 방법 으로 하 는 일 을 지각+initiailize 에서 합 니 다.
최적화 전 pre-main 단계 소모 시간:

최적화 전 pre-main 단계 시간 소모.png
최적화 후 pre-main 단계 소모 시간:

최적화 후 pre-main 단계 시간 소모.png
테스트 환경:Xcode 8.3.3 iOS 10.2 의 시 뮬 레이 터,열 작 동.
비고:테스트 결과 pre-main 단 계 는 일정한 파동 이 있 고 냉 작 동 시 파동 이 더 큰 것 으로 나 타 났 습 니 다.여기 캡 처 는 중간 자릿수 수준 입 니 다.
열 이 작 동 하 는 것 을 볼 수 있 습 니 다.pre-main 단 계 는 시간 이 어느 정도 떨 어 집 니 다.
2.main()단계 의 최적화
2.1.그 중 100 ms 의 dispatch 제거after...코드 를 검사 하기 전에 일부러 시작 그림 에 100 ms 를 더 표시 하 게 합 니 다.무슨 논리 인지 모 르 겠 습 니 다.
2.2.여러 개의 2 자/3 자 라 이브 러 리 를 로드 지연 시 킵 니 다.TBCrashReporter,TBAccsSDK,UT,TRemoteDebugger,ATSDK 등 이 포함 된다.
2.3.여러 시스템 UI 설정,업무 논리 실행 지연.푸 시 등록,새 버 전 검사,오렌지 설정 업데이트 등 이 포함 된다.
2.4.불필요 한 계산 을 피한다.광고 그림 을 표시 할 지 여 부 를 앞 뒤로 두 번 가 져 옵 니 다.가 져 올 때마다 오렌지 의 설정 정 보 를 역 직렬 화 시 켜 야 합 니 다.설정 의 시작/종료 시간 을 비교 하면 약 20ms 가 걸 립 니 다.현재 의 해결 방안 은 첫 번 째 계산 후 하나의 BOOL 속성 으로 캐 시 하고 다음 에 직접 사용 하 는 것 입 니 다.
2.5.로드 지연&게 으 른 로드 부분 보기.단축 암호 인증 페이지 는 시작 그림 이 사라 진 후 사용자 가 보 는 첫 번 째 페이지 입 니 다.이 페이지 는 그림 의 디 코딩,여러 보기 의 생 성&레이아웃 과 관련 되 기 때문에 view DidLoad 단 계 는 100 ms 정도 걸 립 니 다.현재 해결 방안 은 이 중 암호 입력 상자 보 기 를 viewdAppear 에 불 러 오 는 것 으로 지연 시 키 고 암호 오류 알림 보 기 를 게 으 름 으로 불 러 오 는 데 걸 리 는 시간 을 30m 정도 로 줄 이 는 것 입 니 다.
instruments 의 Time Profiler 분석 을 통 해 최적화 후 시작 속도 가 현저히 향상 되 었 고 didFinishLaunching With Options 는 75ms 정도(iPhone 6s iOS 10.3.3)소모 되 었 다.

시작 시간.png
그 중에서 현재 가장 많은 시간 을 소모 하 는 것 은 단축 암호 인증 페이지(PAPasscodeViewController)의 생 성&레이아웃 이 고,그 다음은 DTLaunchViewController 에서 광고 페이지 를 표시 할 지 여 부 를 판단 하 는 코드 이다.PAPasscodeViewController 를 볼 수 있 는 viewdAppear 는 78ms 가 걸 렸 지만 큰 상관 이 없 었 습 니 다.이때 사용 자 는 지문/비밀 번 호 를 검증 하려 고 페이지 를 보 았 습 니 다.
총괄&후속 계획
1.총화
결론 적 으로 시동 속도 가 최적화 되 는 것 같다.시스템 이 작 동 하 는 동안 일 을 적 게 하도록 하 는 것 이다.물론 우 리 는 프로젝트 에서 어떤 일 을 시작 하 는 동안 했 는 지,시작 속도 에 얼마나 큰 영향 을 미 쳤 는 지 먼저 알 아야 한다.그 다음 에 case by case 에서 프로젝트 코드 를 분석 하고 서브 스 레 드,로드 지연,게 으 른 로드 등 방식 으로 시스템 을 시작 하 는 동안 더욱 쉽게 해 야 한다.
2.후속 계획
2.1 일부 방대 한 라 이브 러 리 를 대체 하고 더욱 경량급 의 해결 방안 을 채택 한다.
2.2.코드 를 정리 하고 중복 되 는 실현 을 제거 하 며 기능 이 중복 되 는 클래스&분류&방법 이 나타 나 지 않도록 한다.
2.3.오프라인 업무 와 관련 된 유형&분류&방법 을 정리 하고 제거 합 니 다.
2.4.그 레이스 케 일 버 전의 작 동 속도 변화 추 세 를 잘 감시 하고 작 동 속 도 를 늦 추 는 문 제 를 조속히 발견 하고 해결 합 니 다.

좋은 웹페이지 즐겨찾기