[궁금시리즈] 2-8. 객체는 언제 생성되고 언제 사라질까?

2 minute read

C#에서는 객체를 생성하는 것이 매우 쉽다.

Player player = new Player();

new 키워드 하나만 작성하면 객체가 만들어진다. 반대로 객체를 삭제하는 코드는 존재하지 않는다.

delete player;

같은 문법도 없다.

그렇다면 객체는 언제 생성되고, 언제 메모리에서 사라질까?

이번 글에서는 객체의 생명주기(Lifetime)를 따라가며 메모리 관리가 실제로 어떻게 이루어지는지 알아보자.


객체 생성

객체는 new를 호출하는 순간 생성된다.

Player player = new Player();

실행 순서는 다음과 같다.

new 호출

↓

Heap에 메모리 확보

↓

생성자 실행

↓

참조 반환

즉, new는 단순히 생성자를 호출하는 것이 아니다.

먼저 Heap에 메모리를 할당하고, 그 위에서 생성자가 실행된다.


생성자(Constructor)

class Player
{
    public Player()
    {
        Console.WriteLine("생성");
    }
}
Player player = new Player();

순서는

Heap 메모리 생성

↓

필드 기본값 초기화

↓

생성자 실행

이다.

생성자는 객체를 만드는 것이 아니라 이미 생성된 객체를 초기화하는 역할을 한다.


참조가 생긴다

Player player = new Player();

메모리는

Stack

player

↓

Heap

Player

이 된다.

여기서 중요한 것은 변수는 객체를 가지고 있는 것이 아니라 객체를 참조한다는 점이다.


참조가 하나 더 생기면?

Player a = new Player();

Player b = a;

메모리는

a ─┐
   │
b ─┘

↓

Player

객체는 하나다.

참조만 늘어난 것이다.


참조가 없어지면?

Player player = new Player();

player = null;

이제

Player

참조 없음

상태가 된다.

하지만 객체는 즉시 삭제되지 않는다.

GC가 나중에 회수한다.


메서드가 끝나면?

void Create()
{
    Player player = new Player();
}

메서드 종료 ↓ Stack 제거 ↓ Heap 객체는 참조 없음 ↓ GC 대상

즉, 지역 변수는 사라졌지만 객체는 GC가 실행될 때까지 Heap에 남아 있다.


객체가 살아남는 경우

Player Create()
{
    return new Player();
}

Player player = Create();

메서드는 종료되었다.

하지만

player

↓

Player

참조가 존재한다.

따라서 객체는 계속 살아있다.


객체가 오래 살아있는 경우

예를 들어

static Player player;

또는

Singleton.Instance

같은 객체는 프로그램이 종료될 때까지 살아있는 경우가 많다.

이러한 객체는 Gen2까지 올라가는 경우가 많다.


객체 수명(Lifetime)

객체는

new

↓

Heap 생성

↓

참조 생성

↓

사용

↓

참조 제거

↓

GC

↓

메모리 회수

라는 생명주기를 가진다.


왜 객체 생명주기가 중요할까?

실무에서 대부분의 성능 문제는 객체 생성 횟수와 객체 수명 때문에 발생한다.

예를 들어

Update()
{
    new Bullet();
}

매 프레임마다 객체를 생성하면

생성

↓

Gen0

↓

GC

↓

생성

↓

GC

가 반복된다.

반면 Object Pool을 사용하면 생성과 삭제를 반복하지 않아 GC 부담이 크게 줄어든다.


객체를 빨리 삭제하면 좋을까?

많은 초보 개발자는

player = null;

을 자주 하면 메모리가 절약된다고 생각한다.

하지만 그렇지 않다.

GC는 참조가 없어졌다고 즉시 실행되지 않는다.

오히려 의미 없는 null 대입은 코드를 복잡하게 만들 수 있다.

정말 필요한 경우가 아니라면 지역 변수는 자연스럽게 스코프를 벗어나도록 두는 것이 좋다.


마무리

객체는 new를 호출하는 순간 Heap에 생성되고, 참조가 모두 사라진 뒤 GC에 의해 회수된다. 생성자, 참조, GC는 각각 독립적인 역할을 담당하며, 이 흐름을 이해하면 메모리 관리의 전체 그림을 볼 수 있다.

특히 성능이 중요한 프로그램에서는 객체를 얼마나 자주 생성하는지, 얼마나 오래 유지하는지가 GC 성능에 직접적인 영향을 미친다.

다음 글에서는 Object Pool은 왜 GC 최적화의 핵심 기법일까?를 알아보며 객체 재사용 전략을 살펴보겠다.


핵심 정리

  • new는 Heap에 메모리를 할당한 뒤 생성자를 실행한다.
  • 생성자는 객체를 만드는 것이 아니라 초기화한다.
  • 객체는 참조가 하나라도 남아 있으면 살아있다.
  • 참조가 모두 사라져야 GC 대상이 된다.
  • 메서드 종료와 객체 삭제는 같은 개념이 아니다.
  • 객체 생성 횟수와 생명주기는 GC 성능에 큰 영향을 준다.
  • 불필요한 null 대입보다 적절한 객체 생명주기 관리가 더 중요하다.