brunch

You can make anything
by writing

C.S.Lewis

by 이승현 Sep 04. 2017

The price of ENUMs

Avoid using enums

The price of ENUMs


열거형(Enum)이란, 자바 1.5에서 추가된 서로 연관된 상수들의 집합입니다.

다른 상수들에 비해 코드가 간결해지고 직관성이 좋아지는 장점이 있어서 안드로이드 코드에서도 다양하게 쓰일 수 있습니다.


#01 Enum codes


하지만 메모리 성능상 문제가 있어서 Enum을 쓰지 말라는 루머 아닌 루머? 가 있는데, 살펴보면 2009년도엔 developers.android.com에서 성능상 Enum을 쓰지 말라던 때가 있었습니다.

그러다가 별다른 설명도 없이 잠깐 이 내용이 사라졌는데 현재는 아래처럼 다시 나타났습니다.

결론은 안드로이드에서 Enum 이용은 지양해야 합니다. 그 이유와 Enum의 대안책에 대해서 작성하겠습니다.


#02 Be careful with code abstractions





Application Heap in System Memory


#03 System memory with app


안드로이드는 앱을 위해 시스템 메모리의 한 부분(Application Heap)을 별도로 할당해둡니다.

그리고 앱을 시작하면 이 공간에 DEX 코드를 넣습니다.

DEX(Dalvik Executable) : 실행 가능 바이트코드 파일


만약 이 DEX 코드 공간이 커질수록 시스템 메모리에 부담이 되고, 가용 메모리 공간이 부족하면 공간을 확보하기 위해서 앱이 종료될 수 도 있습니다.




Application DEX Size


#04 App DEX size


Enum이 DEX 사이즈에 끼치는 영향을 알아보기 위해  예를 들어봅시다.

위에 나타난 앱의 DEX 사이즈가 2556 bytes입니다.


#05 int type constants


int 타입의 상수를 추가하고 이를 기반으로 재컴파일을 하면 DEX 사이즈는 2680 bytes입니다.

int 타입 상수를 추가하니 124 bytes(2680-2556=124)가 늘어났습니다.


#06 enum type constants


이번엔 int 타입 대신 Enum으로 구현해서 비교해봅시다.

Enum으로 구현하니 DEX 사이즈는 4188 bytes입니다.

즉, Enum 타입 상수를 추가하는 것만으로 1632 bytes(4188-2556=1632)가 늘어났습니다.


enum(+1632 bytes) / int(+124 bytes) = 13.161...
int 타입에 비해 약 13배 정도 늘어났습니다.




The price of ENUMs


이처럼 Enum으로 인해 DEX 사이즈가 커지면 Application Heap의 가용 공간이 줄어듭니다.

게다가 Runtime memory overhead도 늘어나게 됩니다.


#07 Runtime memory overhead


보통 Enum 하나를 선언하면 크기가 +20 bytes입니다.

그리고 Enum들을 가지고 있는 Array는 12 bytes입니다. (Dalvik에서는 16 bytes입니다.)


만약 이러한 Enum들이 계속 늘어난다면 가용 메모리가 줄어들고, 결국엔 메모리 부족으로 앱을 종료시켜야 하는 상황이 일어날 수 있습니다.


#08 Many enums


물론 비약적으로 발전하는 하드웨어의 성능이나 OS의 메모리 관리 기술의 발전으로 인해 Enum으로 인해 앱을 종료시키는 상황이 일어나기가 쉽진 않습니다.


하지만 앱 전체에 Enum을 많이 쓰거나, 여러 앱에서 쓰이는 라이브러리 내에 Enum이 많다면, 미비하지만 영향을 미칠 수 있습니다.

실제로 Enum으로 인해 문제가 발생한 후에 고치려고 한다면 생각보다 쉽진 않습니다.


#09 Do not use enum in core


그렇기 때문에 안드로이드 코드를 만들어낸 Core 플랫폼 팀에서는 정말 필수가 아니면 Enum을 이용하지 않습니다.




@IntDef annotation


안드로이드는 Typedef annotation이 있는 Annotation 라이브러리를 제공합니다.

정수 및 문자열 집합으로 구성된 열거형 annotation을 생성하여 다른 유형의 코드 참조에 대한 유효성을 검사할 수 있습니다. Typedef annotation은 특정 매개변수, 반환 값 또는 필드가 특정한 상수 집합을 참조하도록 해줍니다. 또한, 코드 완성을 사용하여 허용되는 상수를 자동으로 제공합니다.


#10 @IntDef annotation


@IntDef은 Enum 대신 이용할 수 있는 Constant Annotation입니다.


@Retention과 함께 새 Annotation을 생성하는데, 이러한 Annotation은 열거 형식을 정의하기 위해 필요한 것입니다.  @Retention(RetentionPolicy.SOURCE) Annotation은 컴파일러에게. class 파일에 열거형 주석 데이터를 저장하지 않도록 지시합니다.


즉, @IntDef를 이용하면 int의 사이즈와 성능의 이점을 그대로 쓸 수 있습니다.


좀 더 자세한 내용은 아래 링크를 참고해 주시기 바랍니다.




Proguard


#11 Proguard


프로가드는 기본적으로 Enum을 int 타입으로 최적화해줍니다.

물론 그 과정에서 여러 문제가 발생할 수 도 있기 때문에 프로가드만 믿고 Enum을 마음대로 쓸 수는 없기 때문에 완벽한 해결책으로는 볼 수 없습니다.








결론은 불가피한 경우가 아니라면 Enum을 쓰지 말자입니다.

실제로 Enum이 미치는 영향이 작기 때문에 크게 신경 쓸 필요 없다는 의견들도 많지만, 대체 가능한 @IntDef를 두고 굳이 이용할 필요는 없어 보입니다. 

작가의 이전글 Sharing Content
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari