스택(Stack): 메소드 호출 시 로컬 변수를 저장하는 메모리 영역. 각 스택 프레임은 메소드 호출 시 생성되고, 메소드가 종료되면 사라집니다.
힙(Heap): 객체가 생성되는 동적 메모리 영역. 객체는 여기 저장되며, 객체를 참조하지 않는 변수가 없어지면 가비지 컬렉션의 대상이 됩니다.
public class GC {
private Object o; // 클래스 멤버 변수 (힙에 저장됨)
private void doSomethingElse(Object obj) {
o = obj;
} // obj는 스택에 저장됨
public void doSomething() { // 메서드 호출, doSomething() 스택 프레임 생성
Object o = new Object(); // 스택에 로컬 변수 o, 힙에 새로운 Object 생성
doSomethingElse(o); // 힙의 Object를 this.o에 할당 (멤버 변수 참조)
o = new Object(); // 새로운 Object를 힙에 생성, 로컬 변수 o가 참조
doSomethingElse(null); // this.o에 null 할당 (멤버 변수 참조 해제)
o = null; // 로컬 변수 o 참조 해제
}
}
doSomething 메서드 호출
doSomething 메서드가 호출되면서 새로운 스택 프레임이 생성됩니다.
Object o = new Object();
힙에 새로운 객체 A가 생성되고, 로컬 변수 o가 이 객체를 참조합니다.
메모리 상태:
스택: o -> A
힙: 객체 A
doSomethingElse(o);
doSomethingElse 메서드가 호출되면서 스택 프레임이 생성되고, 로컬 변수 obj가 o를 참조합니다. 또한, GC 클래스의 인스턴스 변수 this.o가 객체 A를 참조하게 됩니다.
메모리 상태:
스택: o -> A, obj -> A
힙: 객체 A
GC 인스턴스 변수: this.o -> A
o = new Object();
새로운 객체 B가 힙에 생성되고, 로컬 변수 o가 객체 B를 참조하게 됩니다. 이전의 객체 A는 여전히 this.o가 참조하고 있으므로 가비지 컬렉션의 대상이 되지 않습니다.
메모리 상태:
스택: o -> B, obj -> A
힙: 객체 A, 객체 B
GC 인스턴스 변수: this.o -> A
doSomethingElse(null);
doSomethingElse 메서드가 호출되면서 this.o는 이제 null을 참조하게 됩니다. 이로 인해 객체 A는 더 이상 참조되지 않으므로 가비지 컬렉션의 대상이 됩니다.
메모리 상태:
스택: o -> B, obj -> null
힙: 객체 A (GC 대상), 객체 B
GC 인스턴스 변수: this.o -> null