다음은 최종 값 유형 지역 변수가 아닌 최종 참조 유형 필드가있는 약간 다른 예입니다.
public class MyClass {
public final MyOtherObject obj;
}
MyClass의 인스턴스를 만들 때마다 MyOtherObject 인스턴스에 대한 나가는 참조를 만들고 GC는 라이브 개체를 찾기 위해 해당 링크를 따라야합니다.
JVM은 마크 스윕 GC 알고리즘을 사용하는데, 이는 GC "루트"위치 (현재 호출 스택의 모든 객체와 같이)에있는 모든 라이브 참조를 검사해야합니다. 각 라이브 개체는 살아있는 것으로 "표시"되고 라이브 개체가 참조하는 모든 개체도 살아있는 것으로 표시됩니다.
표시 단계가 완료된 후 GC는 힙을 스윕하여 표시되지 않은 모든 개체에 대한 메모리를 해제하고 나머지 활성 개체에 대한 메모리를 압축합니다.
또한 Java 힙 메모리가 "젊은 세대"와 "이전 세대"로 분할된다는 사실을 인식하는 것이 중요합니다. 모든 개체는 초기에 젊은 세대 ( "보육원"이라고도 함)에 할당됩니다. 대부분의 개체는 수명이 짧기 때문에 GC는 젊은 세대의 최근 쓰레기를 제거하는 데 더 적극적입니다. 개체가 젊은 세대의 수집주기에서 살아남는 경우에는 이전 세대 ( "장기 세대"라고도 함)로 이동하여 덜 자주 처리됩니다.
그래서 머리 위에서 "아니오, '최종'수정자는 GC가 작업량을 줄이는 데 도움이되지 않는다"고 말할 것입니다.
제 생각에는 Java에서 메모리 관리를 최적화하는 가장 좋은 전략은 가능한 한 빨리 가짜 참조를 제거하는 것입니다. 사용을 마치 자마자 개체 참조에 "null"을 할당하면됩니다.
또는 더 좋은 방법은 각 선언 범위의 크기를 최소화하는 것입니다. 예를 들어 1000 행 메서드의 시작 부분에 개체를 선언하고 해당 메서드의 범위가 닫힐 때까지 (마지막 닫는 중괄호) 개체가 살아있는 경우 개체는 실제보다 훨씬 더 오래 살아있을 수 있습니다. 필요한.
12 줄 정도의 코드 만있는 작은 메서드를 사용하는 경우 해당 메서드 내에서 선언 된 개체가 더 빨리 범위를 벗어나고 GC는 훨씬 더 효율적인 작업을 수행 할 수 있습니다. 젊은 세대. 절대적으로 필요한 경우가 아니면 개체가 이전 세대로 이동되는 것을 원하지 않습니다.