Integer cache pool, Java, 변수 할당

리브리버·2024년 3월 15일
0

TIL

목록 보기
16/17

Constant Pool

Java 는 작은 정수들인 -128 ~ 127에 대해 캐시를 가지고 있어서 저 범위에 존재하는 수에 대해 Integer.valueOf() 를 사용하여 숫자를 Integer 참조타입으로 변환하여 사용할 경우 항상 캐싱이 되어 동일한 숫자에 대해서는 동일한 주소값을 가지게 됩니다.

해당 내용에 대한 설명은 아래에서 자세하게 볼 수 있습니다.

저 -128 ~ 127 숫자들은 아래 그림과 같이 Constant pool 상수풀이 속해있는 Heap 공간에 존재하고 있습니다.

참고 : escapefromcoding 블로그


valueOf()

그리고 valueOf() 메소드에 대해 잠시 알아보면

ArrayList에 add(i) 를 할때 실제로 숫자 원시타입 값 자체를 넣는것이 아닌 Integer 와 같이 Wrapper 형태로 변환하여 주소값을 넣는것을 알 수 있습니다.

add(i) 이 부분을 잘 생각해보면 사실 리스트에 숫자 그대로를 넣을 수 가 없습니다. 왜냐하면 ArrayList의 제네릭이 Integer이기 때문에 int 형을 사용하지 않기 때문입니다.
하지만 저희가 지금까지 list.add(i) 를 사용할 수 있었던 이유는 아래 예시와 같이 자바 컴파일러가 Integer로 변환해주기 때문입니다.

ArrayList<Integer> list1 = new ArrayList<>();

for (int i = 0; i < 10; i++) {
    list1.add(i); // 개발자 코드
}

ArrayList<Integer> list2 = new ArrayList<>();

for (int i = 0; i < 10; i++) {
    list2.add(Integer.valueOf(i)); // 컴파일러가 변환해준 코드, 실제 내부 동작 코드
}

예시

그렇기 때문에 아래와 같은 현상이 일어나게 됩니다.

// case 1
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1==i2); // True

// case 2
Integer i3 = new Integer(127);
Integer i4 = new Integer(127);
System.out.println(i3==i4); // False

// case 3
Integer i5 = 227;
Integer i6 = 227;
System.out.println(i5==i6); // False

case, 시간 별로 순서대로 설명을 해보자면

case 1

  1. Integer 래퍼 클래스에 숫자 127 할당을 시도합니다.

    • 이때 auto boxing이 발생하여 실제로는 Integer i1 = Integer.valueOf(127) 로 되며 valueOf() 함수가 사용될때에 만약 숫자가 -128 ~ 127 사이에 속해있다면 값을 새로 만들지 않고 Constant Pool에서 캐싱하여 가져오게 됩니다.
    • i1 인스턴스 변수에 대해 선언 및 할당이 완료됩니다.
  2. Integer 래퍼 클래스에 숫자 127 할당을 시도합니다.

    • 이때 1과 동일하게 valueOf() 메서드가 실행되어 선언 및 할당이 진행되는데, 값을 가져올떄 Constant Pool에서 동일한 값을 캐싱하여 가져오게 되므로 값의 주소가 동일하게 됩니다.
    • i1과 동일한 주소를 가진 i2 인스턴스 변수에 대해 선언 및 할당이 완료됩니다.
    • 여기서 i1과 i2가 바라보는 주소값이 동일하다는 얘기는 Heap에 생성된 값 객체의 주소를 동일하게 바라보고 있다는 의미가 됩니다.

숫자 127의 동일한 주소(Integer@720) 대한 예시

case 2

  1. Integer 래퍼 클래스에 Integer 객체를 생성 후 그 객체에 127 값을 넣게 됩니다.

    • 이때 생성자 new 키워드를 통해 객체를 생성하기 때문에 Heap에 127 값을 가진 새로운 객체가 생성됩니다.
  2. 1번과 동일하게 진행되어 새로운 객체를 생성하게 됩니다.

    • 즉, Integer에 존재하는 값만 같을 뿐 생성자를 통해 객체를 새로 생성하는 것이므로 서로 다른 참조값을 가진 객체가 됩니다.

숫자 127의 다른 주소(Integer@721, Integer@722)에 대한 예시

case 3

  1. case 1 과 동일하게 valueOf() 메소드를 통해 숫자를 할당하게 되지만 숫자의 범위가 127을 넘어가게 되므로 Constant Pool에서 캐싱이 일어나지 않아 Heap 공간에서 새로운 227 이라는 숫자를 만들고 해당 숫자를 바라보는 i5 인스턴스 변수를 선언 및 할당을 하게 됩니다.

  2. 1번과 동일하게 이루어지며 이때에도 127을 넘어가므로 227이라는 숫자가 존재함에도 불구하고 새로운 숫자를 생성하여 i6 인스턴스 변수를 선언 및 할당을 하게 됩니다.

숫자 227의 다른 주소에(Integer@723, Integer@724) 대한 예시

정리

숫자 -128 ~ 127 에 대해서는 Heap 공간에 Contstant Pool이 숫자도 존재하므로 해당 공간을 먼저 캐싱할 수 있으며, 캐싱을 함으로써 메모리 절약을 할 수 있는 장점이 있다.

0개의 댓글