티스토리 뷰


Gradle 의 장점과 단점

Gradle은 JVM기반의 빌드 도구이자 강력한 의존성 관리 시스템이다. Maven, Ant 보다 빌드 로직을 커스터마이즈하기 더 편하고 같은 코드 베이스에서 여러 버전의 앱을 빌드할 수도 있다. 하지만 빌드 시간이 꽤나 많이 걸리는 문제가 있다. Gradle 버전이 올라가면서 빌드 시간을 단축시키는 성능도 같이 향상되었지만 설정을 잘만 이용하면 더 효율적으로 빌드 할 수 있다.

프로젝트 Build 시간 확인

gradle 빌드 명령을 활용해서 빌드 시간을 측정할 수 있다.

./gradlew build --profile

위에서 --profile명령은 각 Task 실행에 소요된 시간을 측정하고 데이터를 HTML파일로 덤프하라는 뜻이다. 결과물은 /프로젝트 폴더/build/reports/profile 폴더에서 확인할 수 있다. 먼저 아무 설정도 하지 않은 채 프로젝트 파일을 빌드했을 때 54.86초가 걸렸다.

Task Execution 탭을 확인하면 각 모듈별의 작업마다 걸린 시간을 내림차순으로 리포트 해준다.

메인 모듈인 app 모듈이 33초, edittextlibrary 라이브러리 모듈이 31초정도 소요를 했다. 테스트한 프로젝트는 서브 모듈로 edittextlibrary를 커스터마이즈하기 위해 fork하여 사용하고 있었는데 서브 모듈도 매번 빌드를 해주어야 하기 때문에 jar파일이나 maven으로 의존성을 정의하는 것보다 빌드 시간이 훨씬 오래 걸리는 것을 알 수 있었다. 특히 edittextlibrary의 경우 lint 시간이 16초로 대부분을 차지했는데 매번 lint를 사용할 필요가 없다는 사용하지 않는 것이 빌드 시간을 크게 단축시킨다. 뒤에서 그 방법을 설명하고 있다.

빌드 시간 줄이기 5단계

첫째, Gradle Daemon 사용하기

데몬은 Gradle이 일어나는 인스턴스를 유지하고 빌드가 끝난뒤에도 사라지지 않고 백그라운드에서 대기한다. 즉, Gradle을 빌드할 때마다 초기화해야 하는 시간을 단축할 수 있다.

org.gradle.daemon=true

둘째, Parallel Project Execution

서브 모듈이 많을 수록 효과적인 방법이다. 빌드할 때 각 모듈이 동시에 빌드할 수 있도록 설정한다.

org.gradle.parallel=true

셋째, on demand로 프로젝트 설정하기

Gradle은 일반적으로 프로젝트가 특정 빌드 결과물을 필요한지 여부와 상관없이 모든 프로젝트 Task를 설정한다.

온디맨드로 요구하는 프로젝트만 설정한다면 현재 필요하지 않는 프로젝트를 빌드하지 않음으로써 빌드 시간을 단축할 수 있다. 이 설정 역시 멀티 모듈 빌드에 효과적이다.

넷째, 힙 사이즈 증가시키기

안드로이드 스튜디오 2.0 버전 이후부터는 dex를 프로세스에서 사용해 빌드 시간을 줄인다. 프로세스에서 dex를 사용한다는 것은 하나의 VM에서 여러개의 dex프로세스를 실행하는 것으로 빌드 시간을 줄이는 반면 더 큰 메모리를 요구한다. 즉, 힙 사이즈를 조금 키우는 것이 효과적일 수 있다. 기본 데몬을 위한 힙 사이즈는 1GB이기 때문에 gradle.properties에서 다음과 같이 높일 수 있다.

org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

위에서는 3GB로 설정한 것으로 적합한 힙사이즈는 각자의 기기에서 테스트 해보아야 한다.

다섯째, lint 제거하기

아무것도 설정하지 않았을 때 결과에서 보았듯이 lint에 들이는 시간은 꽤 비싸다. 점진적 빌드에서 매번 린트 체크를 할 필요가 없다면 제거하는 것이 좋다. build.gradle에서 다음과 같이 설정하면 된다.

tasks.whenTaskAdded { task ->
  if(task.name.equals("lint")) {
    task.enabled = false
  }
}


그 외에 기억하면 좋은 것들

  • 프로젝트를 빌드할 때 무언가를 다운로드 한다거나 git 커밋을 한다거나 복잡한 작업은 자제하는 것이 좋다. 빌드 시간에 무거운 작업은 영향을 준다.

  • 동적 의존성을 사용하면 매번 온라인에서 새로운 버전을 체크 하기 때문에 정적인 의존성을 사용하는 것이 좋다.

    compile 'com.android.support:appcompat-v7:23.0.+'//동적인 의존성


결과 (최종 비교)

build.gradle에서 설정한 린트 제거 코드외에 나머지를 모두 설정한 gradle.properties는 다음과 같다.

#Enable daemon
org.gradle.daemon=true

# Try and findout the best heap size for your project build.
org.gradle.jvmargs=-Xmx3072m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

# Modularise your project and enable parallel build
org.gradle.parallel=true

# Enable configure on demand.
org.gradle.configureondemand=true

gradle.properties를 적용하고 나니 54.86초에서 43.49초로 약 21% 빌드 시간을 단축했다. 여기에 lint를 제거하고 나니

21.59초로 맨 처음 빌드와 비교했을 때 60% 빌드 시간이 단축되었다. 하루에 평균 20번 빌드를 한다고 하면 하루에 11분 일주일에 대략 1시간을 아낄 수 있다. 레퍼런스 글에 비해서 미약한 수준이지만 그것은 프로젝트 파일이 우선 그렇게 많이 복잡하지 않아서 일 가능성이 크기 때문에 규모가 늘어날수록 시간 단축 효과는 더 커질 것이다.

마무리

그동안 얼마나 많은 시간을 빌드와 같이 보냈을까. 이젠 매 빌드마다 30초씩 시간을 아낄 수 있다. 하지만 사람의 적응의 동물이라고 적용하자마자 익숙해져서 더 줄일수 있는 방법은 없을까 또 다시 고민하고 있다.

레퍼런스


댓글