2024. 8. 22. 19:35ㆍJAVA
불변 객체는 여러 가지 장점을 가지고 있습니다. 특히 Thread Safe하여 병렬 프로그래밍에서 유용하며, 동기화를 고려하지 않아도 안전하다는 사실은 널리 알려져 있습니다. 하지만 불변 객체에 대해 공부하면서 두 가지 의문이 들었습니다.
- 불변 객체가 가비지 컬렉션(GC)의 성능을 높일 수 있다는 점이 잘 이해되지 않았습니다. 일반적으로 불변 객체는 한 번 생성된 후 수정이 불가능하기 때문에 GC와 어떤 관계가 있을지 궁금했습니다.
- 불변 객체의 상태를 변경할 때마다 새로운 객체를 생성해야 한다는 점에서, 성능 저하에 대한 우려가 있었습니다. 객체를 자주 생성하는 것이 과연 효율적인지에 대해 의문이 들었습니다.
의문을 해결하기 위해서 먼저, 가비지 컬렉션의 대상이 뭔지 알아야합니다.
가비지 컬렉션의 대상
가비지 컬렉션(GC)은 Heap 메모리 영역에서 객체를 관리하며, 더 이상 참조되지 않는 객체들을 제거합니다. GC가 객체를 Garbage로 간주할지 여부는 Reachability에 따라 결정됩니다. 즉, 프로그램의 어느 부분에서도 참조되지 않는 객체는 Garbage로 간주되어 메모리에서 해제됩니다.
구체적으로, Method Area, Stack, Native Stack과 같은 JVM Runtime Area에서 참조되고 있는 객체들은 reachable로 판정되며, GC의 대상에서 제외됩니다. 이러한 참조를 가능하게 하는 영역들을 root set이라고 부르며, root set에 의해 참조되지 않는 객체들은 unreachable로 간주되어 GC의 대상이 됩니다.
이를 통해, 불변 객체를 사용한다고 해서 GC의 대상이 아니게 되는 것이 아니란 것을 알았습니다.
그렇다면, 불변 객체는 어떻게 GC의 성능을 높일 수 있을까요?
GC의 스캔 대상에는 불변 객체 안의 객체가 포함되지 않는다.
불변 객체는 한 번 생성되면 그 상태가 변경되지 않습니다.
이로 인해 불변 객체 내부에서 참조하는 다른 객체들도 변경되지 않는다는 특징이 있습니다.
public class ImmutableObject {
private final Object value;
public ImmutableObject(Object o) { value = o; }
private Object getValue() { return value; }
}
위의 ImmutableObject 객체는 생성된 이후에 수정이 불가능한 불변 객체입니다.
이 객체가 생성되는 과정은 아래와 같습니다.
- Object 타입의 value 객체가 생성
- ImmutableObject의 생성자를 통해 ImmutableObject 객체가 생성
- ImmutableObject 객체가 value 객체를 참조
이러한 점을 고려하여, 가비지 컬렉터는 ImmutableObject만 reachable한지를 확인하면 됩니다. ImmutableObject가 reachable하다면, 그 내부의 value 객체도 자동으로 reachable 하다고 판단할 수 있습니다.
결과적으로, 불변 객체를 사용하면 GC가 객체의 참조 관계를 복잡하게 추적할 필요가 줄어들어, 스캔해야 할 객체의 수가 감소하고 스캔해야 하는 메모리 영역과 빈도도 줄어듭니다.
이로써 첫 번째 의문 "불변 객체가 가비지 컬렉션(GC)의 성능을 높일 수 있다"가 해결되었습니다.
객체의 생성 비용보다 GC의 스캔 범위 축소 비용이 더 크다.
다음 의문은 "불변 객체를 사용할 때, 상태 변경이 필요할 경우 새로운 객체를 생성해야 하는데, 이로 인해 새로운 객체가 자주 생성되면 성능이 저하되지 않을까?" 입니다.
위에 대한 의문은 Oracle Docs에 답변이 되어있습니다.
Programmers are often reluctant to employ immutable objects, because they worry about the cost of creating a new object as opposed to updating an object in place. The impact of object creation is often overestimated, and can be offset by some of the efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.
필자는 위 답변에 대해 아래와 같이 이해하였습니다.
불변 객체를 사용하며 수정해야될 시 불변 객체를 생성하는 비용보다 불변 객체를 사용하며 GC의 스캔 범위가 축소되는 비용이 더 크기 때문에 효율적이다.
결론
불변 객체를 사용하며 얻는 이득이 엄청나므로, 불변 객체를 적극적으로 사용해야겠다고 생각했습니다.
'JAVA' 카테고리의 다른 글
IntelliJ의 Run 버튼의 의미 - Build(빌드)와 Compile(컴파일) (0) | 2023.08.20 |
---|---|
ArrayList는 어떻게 용량을 관리할까? (0) | 2023.07.24 |
불변 객체(Immnutable Object)란?? (1) | 2023.05.27 |
String vs StringBuilder vs StringBuffer (0) | 2023.05.27 |
final에 대하여 (4) | 2023.05.26 |