Search
Duplicate

Java - 힙 오염(Heap Pollution)

글감
Java
작성자
작성 일자
2024/02/08 06:43
상태
완료
공개여부
공개
Date
생성자
작업자

힙 오염

힙 오염(Heap pollution)은 JVM의 힙 메모리 영역에 저장되어 있는 특정 변수나 객체에 맞지 않는 데이터를 참조하여, 해당 데이터를 꺼내려할 때 런타임 에러가 발생할 수 있는 오염된 상태를 말한다.
주로 제네릭을 사용할 때 힙 오염이 발생하는데, 제네릭의 타입 소거 특성과 컴파일러 특성이 합쳐져 힙 오염이 발생한다.

제네릭 힙 오염 과정

힙 오염이 발생하는 상황은 두 가지가 있다.
원시 타입과 매개변수 타입을 동시에 사용하는 경우
확인되지 않은 형변환을 수행하는 경우
ArrayList<String> list1 = new ArrayList<>(); list1.add("홍길동"); list1.add("임꺽정"); Object obj = list1; ArrayList<Double> list2 = (ArrayList<Double>) obj; // 힙 오염 발생!! list2.add(1.0); list2.add(2.0); System.out.println(list2); // [홍길동, 임꺽정, 1.0, 2.0] for(double n : list2) { System.out.println(n); }
Java
복사
위 코드에서 ArrayList<String> 타입을 Object로 업캐스팅 후 ArrayList<Double>로 다운캐스팅하여 힙 오염이 발생하고, for문에서 ClassCastException이 발생하게 된다. 이런 현상은 제네릭에서 타입 소거 때문에 발생한다.
컴파일러는 타입 캐스팅에 대해서, 형변환 대상 객체가 형변환 되었을 때 대입되는 변수에 저장 할 수 있는가만 확인할 뿐 꼼꼼하게 검사하지 않는다.
제네릭 타입 파라미터들은 타입 소거 후 Object로 변환되거나 제거되는데, 위 코드에서는 로 타입이 되어 어떤 타입이든 저장할 수 있기 때문에 컴파일러에서 확인하지 못하는 것이다.

힙 오염 방지책

이러한 힙 오염을 방지하기 위해서 자바에서는 Collections 클래스에 checkList()라는 메서드를 지원한다. checkList() 메서드는 해당 객체에 의도하지 않은 타입의 데이터가 들어온다면, 이를 감지하여 예외를 발생시킨다.
List<String> list1 = Collections.checkedList(new ArrayList<>(), String.class); list1.add("홍길동"); list1.add("임꺽정"); Object obj = list1; List<Double> list2 = (List<Double>) obj; list2.add(1.0); // 에러 발생! list2.add(2.0); System.out.println(list2); for(double n : list2) { System.out.println(n); }
Java
복사
이와 같이 checkList()를 적용하면 실질적으로 다른 타입의 값을 넣는 add(1.0)에서 힙 오염을 감지하고 에러가 발생시키게 된다.