-
Java GC와 Object간 ReferenceJava 2020. 10. 18. 16:04
개요
날씨가 조금씩 쌀쌀해지는 가을이네요. 다들 환절기 감기에 조심하시기 바랍니다.
최근 위플래닛에서 프로젝트를 진행하면서 하나 배운 것이 있습니다. WeakReference란 객체인데요. 처음 접하는 개념이라 이해하기 매우 어려웠지만, GC에 대해서 이해한다면 어렵지 않게 또 배울 수 있는 것이 이 Reference입니다.
아무래도 Android 개발을 하다보면 이제는 Kotlin을 주로 사용하지만, 그래도 GC에 대한 이해는 매우 중요하다고 생각합니다. 그럼 시작하겠습니다.
GC의 원리
Java에서 객체를 생성하게되면 JVM의 Heap area에서 생성이 됩니다.
그리고 이 객체를 Stack에 있는 변수들이 참조하게 되죠.
이 Heap 영역의 오브젝트들은 Stack에 있는 변수들이 참조할 수 있는지 없는지에 대해 Reachable 혹은 Unreachable 한 특성을 가지게 됩니다. 여기서 GC는 Unreachable한 오브젝트들을 대상으로 메모리 할당을 해제하는 역할을 합니다.
그래서 이 부분에 대해서 정확히 이해하려면 메모리와 포인터, JVM의 구조에 대해서 어느정도 이해하는 것이 필요합니다.
ExampleClass tempVar = new ExampleClass(); tempVar = new ExampleClass(); // 위에서 생성했던 ExampleClass는 참조 해제되고 Unreachable Object가 됩니다.
위의 코드에서 보면 Heap area에 두 개의 ExampleClass 객체가 생성됐을 것입니다. 처음에 tempVar를 선언하면서 바로 참조했던 ExampleClass는 두번째 ExampleClass를 생성하면서 참조를 잃게 됩니다. 이 객체를 참조할 수 있는 방법은 없어지게 됩니다. 즉 Unreachable Object가 된 것이죠. 이는 GC의 수거 대상이 됩니다.
Strong Reference
일반적으로 유저가 사용하는 객체 선언 방법은 Strong Reference입니다. new를 통한 객체 생성일 수 도 있고, 혹은 필드 주입이라는 방법을 통해 참조하게 되는 것도 Strong Reference일 수 있습니다.
다시 정리하자면, Java가 제공하는 java.lang.ref 패키지가 제공하는 api를 사용하지 않는 모든 객체 참조는 Strong Reference입니다.
여기서 궁금한게 생깁니다. java.lang.ref는 무슨 목적을 하는 패키지이고 어떤 함수가 있을까요?
oracle 공식 문서를 보게되면 java.lang.ref에 대한 설명이 나와있는데요. ref 패키지는 GC의 제한된 인터랙션을 도와주기 위한 Reference-object 클래스를 제공한다고 나와있습니다. 우리가 일반적으로 사용하는 Strong Reference를 통해서는 GC의 수거 범위와 동작 상태를 제어하기가 어렵습니다. 그래서 ref 패키지의 다양한 클래스들을 통해서 우리가 일정 부분 GC의 행동을 제어할 수 있는 것이죠.
GC에서 제공해주는 Reference-Object 클래스는 다음과 같습니다.
-Phantom Reference
-Soft Reference
-Weak Reference
각각의 클래스에 대한 자세한 설명은 Naver D2의 한 포스팅에서 자세히 확인할 수 있습니다. 시간이 상당히 많이 지난 글이지만 Reference-Object 클래스에 대해 이해하는데 많은 도움이 된 것 같습니다.
Viewmodel과 Navigator간의 WeakReference 사용
위플래닛의 맥북 중고 매매 플랫폼 'Baro'의 MVVM은 Activity와 Viewmodel 사이의 Navigator를 통해 Viewmodel과 Activity간 WeakReference를 유지합니다.
Viewmodel이 WeakReference 클래스 타입의 Navigator를 가지고 있고, 이 Navigator가 Navigator타입을 implement한 Activity를 참조함으로써 Viewmodel이 직접적으로 Activity를 참조하는 것을 막은 것이죠. 이를 통해 Activity의 라이프사이클 관리로 인한 MemoryLeak을 예방할 수 있습니다.
BaseViewModel 클래스는 필드로 WeakReference 타입의 mNavigator를 가지고 있습니다. 이 필드에 필요한 Navigator 값을 주입하기 위해 Field Injection 방식의 함수, setNavigator 함수를 선언하고 있죠.
Activity에서는 참조하고 있는 Viewmodel에 Navigator를 주입합니다.
이 Navigator는 엑티비티가 implement하고 있는 상태입니다.
그리고 마지막으로 Viewmodel에서 Activity를 사용하기 위해 getNavigator를 호출함으로써 직접 Activity의 메소드를 호출하는 것이 아닌 Navigator의 메소드를 호출하고 있습니다. 이를 통해 WeakReference를 구현하게 된 것입니다.
결론
저는 Java를 깊게 공부한 적이 없어서 Reference의 중요성에 대해 잘 몰랐습니다. 하지만 Android를 하게 되면서 점점 더 객체들 간의 참조가 중요하다는 것을 배우고 있습니다. 특히 Activity의 Lifecycle과 관련해서 MemoryLeak을 야기할 수 있는 부분이 있기 때문에 이를 사전에 방지하는 것이 중요하죠. 이 GC의 원리와 Reference에 대해서 조사하고 공부하다보면 분명히 Java 기반의 많은 프로그래밍을 하는데 도움이 되리라 생각합니다.
참고 사이트
https://yaboong.github.io/java/2018/06/09/java-garbage-collection/
https://d2.naver.com/helloworld/1329
https://d2.naver.com/helloworld/329631'Java' 카테고리의 다른 글
Java의 Singleton Pattern에 대하여 (0) 2021.05.26 Abstract Class와 Interface의 차이 (0) 2021.04.13 Java에서 동시성 관리 - Synchronization (0) 2020.12.29 Java로 구현하는 DFS 알고리즘 (0) 2020.02.24