Java Garbage Collector와 메모리 관리
Java의 Garbage Collector(GC)가 어떻게 메모리를 관리하는지, 그리고 메모리 릭을 방지하는 방법을 살펴봅니다.
GC의 기본 동작
GC가 데이터가 필요 없다고 판단하는 조건:
- 스레드가 종료되었을 때, 해당 스레드에서 참조하고 있던 모든 데이터를 반환합니다.
- 단, 다른 스레드가 해당 데이터를 참조하고 있다면 반환하지 못합니다.
바로 이 지점에서 메모리 릭이 발생할 수 있습니다.
Anonymous 클래스와 메모리 릭
문제 상황
Anonymous(익명) 클래스로 구현된 인스턴스는 생성된 위치의 외부 클래스에 대한 암시적 참조(implicit reference)를 가집니다.
예를 들어, MainActivity 내의 로컬 메서드에서 생성된 익명 클래스 인스턴스는 MainActivity 인스턴스에 대한 참조를 가집니다.
public class MainActivity {
public void someMethod() {
// 이 익명 클래스는 MainActivity에 대한 implicit reference를 가짐
Runnable runnable = new Runnable() {
@Override
public void run() {
// ...
}
};
// 다른 스레드에 전달
new Thread(runnable).start();
}
}
결과:
- 다른 스레드가 이 anonymous 인스턴스를 가지고 있다면, MainActivity 인스턴스도 함께 참조됩니다.
- 해당 스레드가 종료되기 전까지는, 메인 스레드가 종료되어도 MainActivity 인스턴스는 GC에 의해 반환되지 않습니다.
해결 방법
- static 내부 클래스 사용
- WeakReference 사용
- Lambda 사용 (컨텍스트에 따라)
final 지역 상수의 메모리 관리
final 지역 변수도 해당 변수를 참조하는 객체가 없을 경우 메모리 힙에서 반환됩니다.
변수가 참조되는 경우
-
해당 메서드가 호출되고 있을 때
- 메서드 호출 시 사용할 변수들을 모두 불러옵니다.
- 메서드가 종료되면 일반 변수는 반환됩니다.
-
final지역 상수는 메모리 힙에 있어 메서드가 끝나도 바로 반환되지 않습니다. - 메서드 처리 중에는 지역 변수가 해당 상수를 참조하고 있어 반환되지 않습니다.
-
내부 anonymous class가 생성되었을 때
- Anonymous class는 외부 클래스에 대한 implicit reference와 함께
final지역 상수에 대한 reference도 가집니다. - Anonymous class가 모두 반환될 때 함께 반환됩니다.
- Anonymous class는 외부 클래스에 대한 implicit reference와 함께
WeakReference
WeakReference는 생명주기가 있는 컴포넌트를 참조할 때 유용합니다.
특징
- 참조하는 객체의 생명주기가 끝나면, GC가 해당 객체를 수거할 수 있습니다.
- 컴포넌트가 살아있을 때만 처리하고 싶은 경우에 사용합니다.
사용 예시
public class PhotoManager {
private WeakReference<PhotoView> mImageWeakRef;
public void init(PhotoView photoView) {
mImageWeakRef = new WeakReference<PhotoView>(photoView);
}
public PhotoView getPhotoView() {
if (mImageWeakRef != null) {
return mImageWeakRef.get(); // null이 반환될 수 있음
}
return null;
}
void recycle() {
if (mImageWeakRef != null) {
mImageWeakRef.clear();
mImageWeakRef = null;
}
}
}
주의사항
-
WeakReference.get()은 객체가 GC에 의해 수거되었다면null을 반환합니다. - 반환된 값은 항상 null 체크를 해야 합니다.
Reference 타입 비교
| 타입 | 설명 | GC 동작 |
|---|---|---|
| Strong Reference | 일반적인 참조 | 참조가 있으면 수거 안 함 |
| Weak Reference | 약한 참조 | GC 실행 시 수거 대상 |
| Soft Reference | 부드러운 참조 | 메모리 부족 시 수거 대상 |
| Phantom Reference | 유령 참조 | 이미 finalize된 객체 추적용 |
메모리 릭 방지 체크리스트
- Anonymous 클래스 대신 static 내부 클래스 사용
- 생명주기가 있는 컴포넌트는 WeakReference로 참조
- 더 이상 필요 없는 리스너/콜백은 명시적으로 해제
- 컬렉션에 추가한 객체는 필요 없을 때 제거
- 스레드 작업 완료 후 참조 정리
Originally published at https://dss99911.github.io
Top comments (0)