결론은 먼저 얘기 하자면, 자바에서 final 키워드를 쓴 이유가 가비지 콜렉션을 빨리 일으키게 하려고 썼다면, 그건 아니라는 얘기 인 듯 합니다.
final 키워드 말고, 해당 객체를 널 처리 하는 것이 낫다라는 개념으로 받아 들입니다.
오늘 내 동료랑 자바에서 가비지콜렉션 (성능)을 향상 시키기 위한 final 키워드의 사용법에 대해서 얘기를 나눴습니다.
예를들어, 다음과 같은 메서드가 있다고 치면:
public Double doCalc(final Double value)
{
final Double maxWeight = 1000.0;
final Double totalWeight = maxWeight * value;
return totalWeight;
}
'메서드를 final로 선언하는 것이 메서드가 사용된 후에 메서드내에 사용되지 않는 변수들에 대한 메모비를 가비지콜렉션이 정리 할때 도움을 줄수 있을 것이다.'
이 말이 맞을까요?
다음은 final 값 유형 지역 변수가 아닌 final 참조 유형 필드를 가진 약간 다른 예를 들어 보겠습니다.
public class MyClass {
public final MyOtherObject obj;
}
MyClass의 인스턴스를 만들 때마다 MyOtherObject 인스턴스에 대한 나가는 참조(outgoing reference)를 만들것이며 GC는 해당 링크를 따라가면서 살아있는 객체들을 찾아 볼 것입니다.
JVM은 GC "루트" 위치(현재 호출 스택의 모든 객체들)에 있는 살아있는 모든 참조들를 검사해야만 하는 마크 스윕 GC 알고리즘을 사용합니다. 각 살아있는 객체는 살아 있는 것으로 "marked"되며 라이브 객체가 참조하는 모든 객체도 살아 있는 것으로 표시됩니다.
표시(mark) 단계가 완료된 후 GC는 힙에 대한 정리를 하고 표시되지 않은 모든 객체에 대한 메모리를 해제하고 나머지 활성 객체에 대한 메모리를 압축합니다.
또한 중요한 점은 Java 힙 메모리가 "young generation"와 "old generation"로 분할된다는 점을 알고 있어야 한다는 것입니다.
모든 객체는 초기에 young generation("보육원-the nursery"이라고도 함)에 할당됩니다.
객체가 Young Generation의 수집 주기에서 살아남으면 느리게(덜 자주) 처리되는 Old Generation("tenured Generation"이라고도 함)으로 이동됩니다.
그래서 제 머릿속에서 "아니요, 'final' 수정자는 GC가 작업 부하를 줄이는 데 도움이 되지 않습니다."라고 말하고 있네요.
제 생각에는 Java에서 메모리 관리를 최적화하기 위한 최선의 전략은 가짜 참조를 가능한 한 빨리 제거하는 것입니다. 객체 참조를 사용하는 즉시 개체 참조에 "null"을 할당하면 됩니다. 또는 더 좋은 방법은 각 선언 범위의 크기를 최소화하는 것입니다.
예를 들어, 1000줄 메서드의 시작 부분에서 객체를 선언하고 해당 메서드의 범위가 닫힐 때까지(마지막 닫는 중괄호) 객체가 활성 상태인 경우 개체는 실제 필요한 상태보다 훨씬 더 오래 활성 상태를 유지할 수 있습니다.
12줄 정도의 코드로 작은 메서드를 사용하는 경우 해당 메서드 내에서 선언된 개체는 더 빨리 범위를 벗어나고 GC는 훨씬 더 효율적인 젊은 세대 내에서 대부분의 작업을 수행할 수 있습니다.
우리는 절대적으로 필요한 경우가 아니면 객체가 old generation로 이동되는 것을 원하지 않을 것입니다.
'프로그래밍' 카테고리의 다른 글
Where, Group by, Holding 및 Order by 절 (0) | 2022.11.27 |
---|---|
자바에서 Bit Masking (1) | 2022.11.26 |
[C#]제공자가 oracle 클라이언트 버전과 호환되지 않습니다 (0) | 2022.11.24 |
Python 101: Equality(동일성) vs Identity(동등성) (0) | 2022.11.23 |
Bucket Sort 알고리즘 (0) | 2022.11.21 |