객체의 생명주기 (Object Life Cycle)

SEUNGJUN·2024년 2월 7일

객체가 생성되고, 최종적으로 소멸되기까지의 과정을 객체의 생명주기라고 한다.

프로그램이 실행을 하게 되면 프로그램 내부의 객체, 변수, 코드 등은 메모리에 저장이 되게 된다.

메모리 영역

1. 코드(Code) 영역

  • 프로그램 코드가 저장되는 영역
  • 읽기 전용

2. 데이터(Data) 영역

  • 전역변수, 정적 변수, 상수 등이 저장되는 영역.
  • 초기화된 전역 변수와 정적 변수는 초기값을 가지고 있다.

3. 스택(Stack)

  • 지역 변수와 메서드 호출을 관리하는 영역
  • 함수 호출시 스택 프레임이 생성되고, 함수 실행이 끝나면 스택에서 제거된다.
  • 메모리 할당과 해제가 빠르지만, 크기가 작아서 주로 간단한 데이터를 저장.

4. 힙(Heap)

  • 동적으로 할당된 데이터, 객체, 배열 등이 저장되는 영역.
  • 개발자가 직접 메모리를 할당하고 해제해야함.
  • 크키가 동적으로 변할 수 있고, 힙에 저장된 데이터는 명시적으로 해제되지 않으면 계속 유지.

객체 생명주기 단계

1. 생성 (Instantiation)

  • 객체가 생성되는 단계. 메모리 공간이 할당되고, 생성자(constructor)가 호출되어 초기화 작업이 수행된다. 객체가 생성되면 해당 객체의 인스턴스 변수들이 메모리에 존재된다.

2. 초기화 (Initialization)

  • 객체가 생성된 후에 초기화 작업이 이루어 진다. 필요한 속성이나 상태를 설정하고, 다른 객체와의 관계를 설정할수 있다.

3. 사용 (Utilization)

  • 객체가 초기화된 후에는 프로그램에서 사용하게 된다. 메서드 호출, 데이터 조작 등 작업을 하게 된다.

4. 소멸 (Destruction)

  • 객체를 모두 사용하고 더이상 필요성을 느끼지 못할때, 메모리가 해제되고 소멸하는 단계가 찾아오게 됩니다. 일반적으로 가비지 컬렉터에 의해 처리가 되며, 더 이상 참조되지 않는 객체는 제거가 되게 된다. 객체가 소멸될 때는 소멸자(destructor)가 호출되거나, 가비지 컬렉션 과정에서 처리된다.

가비지 컬렉터(Garbage Collector)

  • 메모리 관리를 도와주는 자바 가상 머신 JVM(Java Virtual Machine)의 일부로 프로그램에서 더 이상 참조되지 않는 객체를 탐지하고, 이러한 객체들을 자동으로 메모리에서 해제하여 더 이상 사용되지 않는 메모리를 회수한다. 이렇게 되면 메모리 누수(memory leak)을 방지할수 있고, 개발자가 명시적으로 메모리 관리를 신경쓰지 않아도 된다.

메모리 누수(memory leak)

  • 프로그램에서 동적으로 할당한 메모리를 해제하지 않고 계속 보유하는 상태, 프로그램이 실행되는 동안 메모리 사용량이 계속 증가하면서, 결국 시스템의 메모리 부족으로 인한 성능 저하및 프로그램 종료를 야기 할수 있다.
public class MyClass {
    // 생성자: 객체가 생성될 때 호출되는 메서드
    public MyClass() {
        System.out.println("Object is created.");
    }

    // 초기화 메서드
    public void initialize() {
        System.out.println("Object is initialized.");
    }

    // 사용 메서드
    public void performOperation() {
        System.out.println("Object is performing an operation.");
    }

    // 소멸자: 객체가 소멸될 때 호출되는 메서드
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Object is being destroyed.");
    }

    public static void main(String[] args) {
        // 객체 생성
        MyClass myObject = new MyClass();

        // 초기화
        myObject.initialize();

        // 사용
        myObject.performOperation();

        // 객체가 더 이상 필요하지 않을 때, 소멸
        myObject = null;
        System.gc(); // 가비지 컬렉터 호출
    }
}

예시를 보면 객체가 생성되면서 생성자가 호출이되고, 초기화 매서드를 호출해서 초기화 작업이 이루어지며, 사용 메서드를 통해서 객체가 작업을 수행하게 된다. 그리고 'myObject = null;'을 통해서 객체에 대한 참조가 해제되고 가비지 컬렉터에 의해 더이상 참조되지 않는 객체를 메모리에서 해제하게 된다.

스택 메모리 저장과정

  • 스택은 메모리의 한 영역으로, 후입선출(Last In, Frist Out) 구조로 데이터를 저장하고 꺼내온다. 이때 데이터는 스택 프레임(Stack Frame)이라는 작은 단위 블록으로 저장되며, 각각의 스택 프레임은 함수 호출이나 블록의 시작 지점에서 생성되고, 함수 종료나 블록 끝에서 제거 된다.
public class StackExample {
    public static void main(String[] args) {
        int result = addNumbers(3, 4);
        System.out.println("Result: " + result);
    }

    public static int addNumbers(int a, int b) {
        int sum = a + b;  // 지역 변수 sum 선언
        int result = multiplyByTwo(sum);  // 다른 함수 호출
        return result;
    }

    public static int multiplyByTwo(int num) {
        int result = num * 2;  // 지역 변수 result 선언
        return result;
    }
}

예시를 보면서 정리를 해보면

1. main 메서드가 호출

  • main 메서드의 스택프레임(1층)이 쌓인다.

2. addNumbers 메서드를 호출

  • addNumbers 메서드의 스택프레임(2층)이 쌓인다.
    이때 계산을 하고 multiplyByTwo 메서드를 호출한다.

3. multiplyByTwo 메서드 호출

  • multiplyByTwo 메서드의 스택프레임(3층)이 쌓인다.

4. multiplyByTwo 메서드 제거

  • multiplyByTwo 메서드의 값이 return 된 이후 해당 스택프레임이 제거된다.

5. addNumbers 메서드 제거

  • addNumbers 메서드의 데이터를 return 하고 해당 프레임 제거.

6. main 메서드 제거

  • main 메서드에서 최종적으로 계산된 result 값은 출력하고 스택프레임 제거가 된다.

힙 메모리 저장과정

  • 객체나, 배열등의 데이터가 이곳에서 관리된다.
public class HeapExample {
    public static void main(String[] args) {
        // 객체 생성: 힙에 메모리가 할당됨
        MyClass obj1 = new MyClass("Object 1");

        // 다른 객체 생성: 새로운 힙 메모리가 할당됨
        MyClass obj2 = new MyClass("Object 2");
    }
}

class MyClass {
    private String data;

    // 생성자
    public MyClass(String data) {
        this.data = data;
        System.out.println(data + " is created.");
    }
}

/* 실행결과
Object 1 is created.
Object 2 is created. 
*/
  1. 객체 생성(new MyClass("Object 1"))
  • MyClass의 객체가 생성될 때, 힙에 해당 객체의 인스터스가 저장된다.
  • 생성자가 호출되어 초기화 작업이 수행되고, 해당 객체의 데이터 Object 1이 힙에 저장된다.
  1. 객체 생성(new MyClass("Object 2"))
  • 다른 객체를 생성할 때도 마찬가지로 힙에 새로운 메모리 공간이 할당이 되고, 객체 데이터가 힙에 저장이 된다.

힙에 저장된 메모리는 가비지 컬렉터에 의해 관리가 되며, 더 이상 참조되지 않는 객체는 자동으로 해제 처리 된다. 객체의 생명주기는 참조에 따라 동적으로 변하고, 이렇게 되면 메모리 누수를 방지하고, 프로그램이 효율적으로 동작 하도록 할수 있다.

profile
RECORD DEVELOPER

0개의 댓글