성능을 개선할 수 있는 다양한 방법과 툴
작성자 : 박태임
Present Time : 2018–07-05-THU
- 병목을 발견하자
- 병목현상이란?
- StrictMode
- 레이아웃 최적화
- 레이아웃을 단순하게
- lint로 다양한 문제를 검사하자
- lint를 사용해보자
- Hierarchy Viewer로 레이아웃 구조를 파악하자
- 메모리를 의식하고 개발하자
- Memory Leak (메모리 누수)
- Android Profiler
- LeakCanary
- 마무리
- 소감
- 출처
전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상.
화면 그리기가 느리거나 사용자 조작에 바로 반응하지 못하는 주된 원인 중 하나로서 메인 스레드의 처리가 블록되는 것을 들 수 있다. 메인 스레드가 블록되지 않았는지 확인하려면 StrictMode를 설정한다.
StrictMode는 개발할 때 이용할 수 있는 모드로서 크게 스레드에 관한 정책과 가상 머신에 관한 정책을 쓸 수 있다.
메인스레드에서 디스크 접근, 네트워크 접근 등의 비효율적인 작업을 하려는 것을 감지하여 프로그램이 부드럽게 작동하도록 돕고 빠른 응답을 가지도록 한다.
메인 스레드에서 사용성을 떨어뜨리는 작업들을 하지 않도록 Log, 강제종료 등의 방법으로 개발자에게 알려주는 API이다.
메인스레드에서 실행되지 않아야 할 처리가 메인 스레드에서 실행되었는지 감지하는 정책을 설정한다.
주로 객체의 메모리 누수나 보안에 관한 사항을 감지하는 정책
정책위반을 감지한 후의 페널티 설정은 penalty~() 라는 메소드를 호출해서 할 수 있다.
-
penaltyLog() : Logcat에 로그 출력
-
penaltyDeath() : 앱을 강제 종료 시킴
-
penaltyDialog()
-
penaltyFlashScreen()
등등
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() // 디스크 읽기 감지
.detectDiskWrites() // 디스크 쓰기 감지
.detectNetwork() // 네트워크 액세스 감지
.penaltyLog() // 위반시 Logcat에 출력
.build()); // 정책 빌드
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects() // 액티비티 서브클래스 leak 감지
.detectLeakedClosableObjects() // File/Network IO 관련 사용시 close()를 명시적으로 호출 안아호 종료할 경우 나오는 리소스 leak 감비
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
레이아웃도 ANR의 원인 중 하나가 될 수 있으므로 사전에 예방하는 것이 중요하다. View 클래스에서는 레이아웃을 화면에 그릴 때 다양한 화면 크기에 맞추기 위해 화면에 그리는 레이아웃에 대한 연산을 해야 한다. 그 이유는 다양한 화면 크기를 지원하려면 레이아웃에는 여러 연산이 필요하기 때문이다. 따라서 사용하는 View의 수가 늘어 나면 그만큼 레이아웃을 오픈하는 데 시간이 걸릴 수 밖에 없다.
설계단계에서 최대한 심플한 레이아웃을 구성하는 것이 효과적인 방법이다. 버튼, 텍스트뷰, 체크 박스 등 UI 컴포넌트 자체의 사용을 줄인다는 것은 불가능 하지만, ViewGroup을 상속받는 레이아웃 관련 클래스는 줄일 수 있다.
LinearLayout안에 LinearLayout을 중첩 사용하여 복잡한 레이아웃을 구현하는 대신, RelativeLayout을 효율적으로 활용할 수 있는지 검토해보자.
Android SDK Tools에 부속된 lint는 잠재적인 오류와 퍼포먼스에 문제가 있을 듯한 코드를 검사해서 보고해 준다.
- 문자열 리소스 번역 여부 검사 (미번역 감지)
- 레이아웃 퍼포먼스
- 이용하지 않는 리소스 발견
- 접근성, 국제화 문제 발견 (문자열 하드코딩 발견)
- 이용하는 아이콘 (중복 발견)
- 이용성
http://tools.android.com/tips/lint-checks
직접 내 프로젝트에 적용을 해 보았다.
- Analyze -> Inspect Code 를 실행한다.
- 다음과 같은 경고가 표시된다.
[Missing 'contentDescription' attribute on image]
=> android:contentDescription="@string/contentDescription" 을 추가해준다.
이유 ) 이미지가 로딩 되지 않거나 시각장애인을 위한 음성 안내 기능 등을 위해 이미지의 설명이 필요하다.
[This LinearLayout should use 'android:layout_height="wrap_content"']
[참고] 경고를 표시되지 않게 하려면?
<LinearLayout
// Code..
tools:ignore="UseCompoundDrawables"/>
안드로이드 스튜디오의 Hierarchy Viewer는 레이아웃의 뷰 계층 구조를 보여주는 개발자용 도구이다.
레이아웃을 트리 형태로 표시해 줄 뿐만 아니라 그리는 데 걸리는 시간 측정, 뷰의 클래스 이름과 id 등 다양한 정보를 얻을 수 있다.
또한, 이 툴을 이용해서 레이아웃 성능 측면에서의 병목현상을 발견할 수 있다.
- Tools -> Android -> Android Device Monitor
- Window -> Open Perspective… -> Hierarchy View
- 뷰 계층 구조를 확인하자!!
레이아웃을 좁고 깊게 만들기보다, 얇고 넓게 만들어 레이아웃의 중첩을 줄이면 성능을 향상시킬 수 있다.
위 예시의 레이아웃 성능은 중첩된 레이아웃이 많아 개선시켜야 할 필요가 있다.
메모리가 부족해지면 가비지 콜렉션이 빈번하게 발생하여 성능에 영향을 준다. 또한, 메모리 누수가 발생하면 해제되어야 할 메모리가 해제되지 못해 결국 OutOfMemoryError라는 형태로 앱이 다운된다.
그러므로 메모리를 의식하고 개발하는 것은 아주 중요하다.
프로그램이 필요하지 않은 메모리를 계속 점유하고 있는 현상.
할당된 메모리 사용후 반환하지 않는 것이 누적되면 메모리가 낭비된다.
이 그래프를 통해 실시간으로 이용할 수 있는 힙 메모리와 확보된 메모리의 양을 확인할 수 있다.
Square 사(Retrofit, Picasso 등 개발) 에서 개발한 라이브러리로 메모리 누수를 감지하는데 유용하다.
장점
- 적용이 매우 쉽다.
- Leak이 발생하면 시각적으로 알 수 있다.
단점
- Activity Leak을 확인하는 것만 가능하다.
- Activity의 Destroy 시점에서 검사를 진행하므로 화면 전환속도가 조금 느리다.
- release버전에서는 LeakCanary가 동작하지 않도록 빈 라이브러리를 컴파일하거나, 라이브러리를 제거해야 한다.
-
build.gradle의 depencies에 추가
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' }
-
onCreate에서 메모리 누수 감지 활성화
@Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { return; } LeakCanary.install(this); }
-
Manifest에 Application 추가
<application android:name=".LeakCanaryApplication"
-
앱을 테스트하다보면 Notification이 뜬다. 해당 액티비티에 Leak이 존재한다는 것이다.
그 Notification을 클릭하면, Leak이 발생한 이유를 보여주는 화면이 나온다.
이번 발표를 준비하면서 메모리관리의 중요성과 여러가지 Memory Leak을 관리해주는 툴들을 많이 알게 되었다. 그냥 무작정 개발하는게 아니라 앱 성능을 생각하면서 개발해야 한다. 이번에 알게된 것들을 성능 개선을 위해 실제 프로젝트에 적용해 볼 것이다.
특히, 레이아웃을 많이 쓰면 안좋다는 것과 그 이유를 이번에 처음 알게되었다. 레이아웃을 좀 더 신경써서 개발해야겠고 ConstraintLayout을 사용할 필요성을 느껴 공부를 하기로 결심했다.
- 안드로이드 개발 레벨업 교과서 (쯔쯔이 슌스케 외 4명 지음)
- 완벽한 안드로이드 앱을 만드는 실무 노하우 139 (기다 마나부 외 7명 지음)