본문 바로가기

개발

자바 ArrayList 의 default size 는 10 맞을까?

언제부터인가 ArrayList 를 기본 생성자로 생성했을 때

default size 는 10으로 외우고 있었습니다.

혹여나 하는 마음에 코드를 가볍게 들여다봤는데 생각과는 달랐습니다.

 

ArrayList 는 아래와 같이 동작하고 있었습니다.

1. 미리 만들어진 (static) 빈 배열로 초기화

2. 값을 한개라도 추가하면 default size 인 10 길이의 배열 할당

 

코드를 보면서 어떻게 구현이 되어있는지 확인해 보겠습니다.

openjdk11 을 사용하였습니다.

 

기본 생성자를 사용했을 때


ArrayList의 기본 생성자

this.elementData 는 ArrayList 에서 데이터를 저장하는 1차원 배열의 변수입니다.

ArrayList 의 기본 생성자를 따라가 보면 위와 같은 상수로 초기화되는 것을 볼 수 있습니다.

저 상수의 값을 확인해 보겠습니다.

그 값은 빈 배열이었습니다.

ArrayList 의 default size 는 10이라고 알고있었는데 빈 배열로 초기화를 하고 있었습니다.

하지만 static 변수인 것으로 보아 임시로 할당해 주는 것 같습니다.

ArrayList 의 사이즈가 어떻게 변하는지 보기 위하여 add 메소드를 따라가 보았습니다.

 

위 과정을 요약하면 다음과 같습니다.

1. add 메소드 호출

2. 값을 추가하기 전에 데이터 저장하는 array 의 길이와 데이터의 개수를 기록하는 size 값과 비교하니 0 으로 같아서 grow 메소드 호출

3. grow 는 늘어난 길이의 array 사이즈를 반환하는 newCapacity 메소드를 호출

4. newCapacity 에서는 DEFAULT_CAPACITY 를 리턴

그럼 DEFAULT_CAPACITY 의 값이 몇인지 확인해 보겠습니다.

맨 처음 생각했던 ArrayList 의 default size 인 10 을 볼 수 있습니다.

 

이와 같이 ArrayList 는 기본 생성자로 생성한다면 static 변수에 먼저 초기화된 빈 배열을 할당합니다.

그리고 이 ArrayList 를 사용 시에 기본 사이즈인 10으로 늘려줍니다.

왜 이렇게 개발되었을지 찾아보다가 stackoverflow 에서 이와 관련된 개발자들의 코멘트를 볼 수 있었습니다.

it was very common (perhaps absurdly common) for applications to allocate ArrayList instances of the default size and then never add any elements. Lazily allocating the backing array in this case saved significant amounts of heap.

어플리케이션에서 ArrayList 를 기본 사이즈로 생성한 후 사용하지 않는 경우가 매우 흔했습니다.
이런 경우에 Lazy allocation 은 상당한 heap 메모리를 아낄 수 있습니다.

 

초기화 size 를 파라미터로 받는 생성자를 사용했을 때


그렇다면 기본 생성자가 아닌 size 를 인자로 받는 생성자로 ArrayList 를 초기화한다면 무엇이 달라지는지

코드를 통해 알아보겠습니다.

  1. ArrayList 생성자에 0 보다 큰 수를 전달하면 바로 그 크기만큼의 배열이 할당됩니다.
  2. 만일 0 을 전달한다면 EMPTY_ELEMENTDATA 라는 값으로 초기화됩니다.

새로운 값이 등장했습니다. EMPTY_ELEMENTDATA 는 어떤 값인지 확인해보겠습니다.

이 값 역시 맨 처음 봤던 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 값과 똑같이 static 변수이고 빈 배열로 초기화되어 있습니다.

왜 같은 값이 2개로 나뉘어 있을까요?

DEFAULTCAPACITY_EMPTY_ELEMENTDATA 변수 선언 위에 아래와 같은 주석이 달려있습니다. 

We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added.
첫 번째 엘리먼트를 추가할 때 얼마큼 확장해야 하는지 알기 위해 EMPTY_ELEMENTDATA 과 구분합니다.

위에서 봤던 코드 중 일부를 확인해 보면 위 말을 이해할 수 있습니다.

값을 저장하는 배열이 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 일 때만(기본 생성자로 생성했을 떄) 빨간 박스의 if 문을 타서 10으로 초기화됩니다. 즉, EMPTY_ELEMENTDATA 는 초기화 값을 0으로 명시적으로 주었지만 Lazy allocation 을 위해 static 변수의 값을 임시로 할당하고 값을 처음으로 더하면 10으로 되는 게 아닌 1 로 초기화 될 것입니다.

 

 

결론


ArrayList 를 기본 생성자로 생성하면 static 변수에 미리 초기화된 빈 배열이 할당되지만,

값이 한 개라도 추가되면 default size 인 10 크기로 배열을 초기화합니다.

만약 ArrayList 생성자에 초기 size 를 전달한다면 그 크기만큼 배열이 할당됩니다.

하지만 그 size 가 0 이라면 기본 생성자로 생성한 것처럼 static 변수에 미리 초기화된 빈 배열이 할당되고,

값을 더하면 기본 생성자때와는 달리 사이즈가 1부터 점차 늘어납니다.