Java 메모리 구조와 static

상곤·2024년 10월 16일

Java

목록 보기
8/22
post-thumbnail

자바의 메모리 구조는 프로그램 실행 중에 데이터를 어떻게 저장하고 관리하는지에 대한 중요한 개념이다. 이번 포스트에서는 자바의 메모리 구조와 static 키워드의 사용법을 알아보자!


1. 자바 메모리 구조

자바의 메모리 구조는 크게 메서드 영역, 스택 영역, 힙 영역으로 나뉜다.

메서드 영역 (Method Area): 클래스 정보, static 변수, 상수 풀이 저장되는 영역으로, 프로그램 실행 중에 사용하는 공통 데이터를 저장하고 공유한다.
스택 영역 (Stack Area): 메서드 호출 시마다 새로운 스택 프레임이 생성되며, 메서드가 종료되면(함수의 괄호가 닫히면) 해당 스택 프레임이 제거된다. 각 스레드는 독립적인 스택을 가진다.
힙 영역 (Heap Area): 객체와 배열이 생성되는 영역으로, 가비지 컬렉터(GC)에 의해 더 이상 참조되지 않는 객체는 제거된다. 힙은 영 제너레이션, 올드 제너레이션, 메타스페이스로 나뉘어 객체의 생애 주기에 따라 관리된다.

가비지 컬렉션 (Garbage Collection)

Mark and Sweep: 참조되지 않는 객체를 '마크'하고, 이를 '스윕'하여 힙에서 제거하는 방식으로 메모리를 관리한다.
Generational Collection: 젊은 객체는 영 제너레이션에 할당되고, 오래 살아남은 객체는 올드 제너레이션으로 이동하여 관리된다.


2. 자바 메모리 구조 시각화

아래 코드를 실행하면 메서드 영역, 스택 영역, 힙 영역이 어떻게 작용하는지 확인할 수 있다.

public class MemoryExample {
    public static void main(String[] args) {
        // 힙 영역: 스택 프레임 객체가 힙에 생성
        StackFrame stackFrame1 = new StackFrame("Method Stack Frame 1");
        StackFrame stackFrame2 = new StackFrame("Method Stack Frame 2");

        // 스택 영역: createMethod() 호출로 스택 프레임이 추가
        createMethod(stackFrame1);  // 스택 프레임 1을 처리
        createMethod(stackFrame2);  // 스택 프레임 2를 처리
    }

    // 메서드 영역: 프로그램 실행 중 공통적으로 사용되는 메서드가 저장
    public static void createMethod(StackFrame stackFrame) {
        System.out.println(stackFrame.getFrameName() + " in execution.");
    }
}

// 메서드 영역: StackFrame 클래스와 관련된 정보는 메서드 영역에 저장
class StackFrame {
    private String frameName;  // 힙 영역에 저장되는 인스턴스 변수

    // 힙 영역: 생성자를 통해 인스턴스가 힙에 저장
    public StackFrame(String frameName) {
        this.frameName = frameName;
    }

    // 메서드 영역: getFrameName 메서드가 메서드 영역에 저장
    public String getFrameName() {
        return frameName;
    }
}

스택 영역: 메서드 호출 시 생성되는 공간이다. main() 메서드와 createMethod() 메서드의 스택 프레임들이 여기에 저장된다.

힙 영역: StackFrame 객체들이 힙에 생성되며, 이 객체들은 frameName 필드를 가지고 있다.

메서드 영역: StackFrame 클래스의 정보와 createMethod() 메서드가 메서드 영역에 저장된다. 인스턴스가 여러 개 생성되어도 메서드는 메서드 영역에 단 한 개만 정의되어 있고, 메서드를 호출시 메서드 영역의 동일한 메서드가 호출된다.


3. 스택과 큐 자료 구조

스택 (Stack)

후입선출 (LIFO): 나중에 넣은 것이 먼저 나오는 구조이다. 자바에서 메서드 호출 시 스택 구조를 사용하여, 메서드가 호출될 때마다 스택에 쌓이고, 종료되면 스택에서 제거된다.

큐 (Queue)

선입선출 (FIFO): 먼저 넣은 것이 먼저 나오는 구조이다. 큐는 선착순 작업에 적합한 자료 구조이다.


4. 스택과 힙 영역의 동작

스택에는 메서드 호출 시 생성되는 지역 변수가 저장되고, 힙에는 객체가 생성되어 저장된다.

class Item {
    private int quantity;

    public Item(int quantity) {
        this.quantity = quantity;
    }

    public int getQuantity() {
        return quantity;
    }
}

public class MemoryExample {
    public static void main(String[] args) {
        System.out.println("main start");
        initiateProcess();
        System.out.println("main end");
    }

    static void initiateProcess() {
        System.out.println("initiateProcess start");
        Item item1 = new Item(5);
        processItem(item1);
        System.out.println("initiateProcess end");
    }

    static void processItem(Item item2) {
        System.out.println("processItem start");
        System.out.println("item.quantity = " + item2.getQuantity());
        System.out.println("processItem end");
    }
}

  1. main() 메서드 호출 (스택 영역)
  • stack: main() 메서드의 스택 프레임 생성.
  • "main start" 출력.
  1. initiateProcess() 호출 (스택 영역)
  • stack: initiateProcess() 메서드의 스택 프레임 생성.
  • "initiateProcess start" 출력.
  1. new Item(5) 호출 (힙 영역)
  • heap: Item 객체 생성, quantity = 5 값 저장.
  • stack: item1 참조 변수가 힙의 Item 객체를 참조.
  1. processItem(item1) 호출 (스택 영역)
  • stack: processItem() 메서드의 스택 프레임 생성, item1 참조 변수가 item2로 전달됨.
  • "processItem start" 출력.
  1. item2.getQuantity() 호출 (힙 영역)
  • heap: Item 객체의 quantity = 5 값을 읽어옴.
  • "item.quantity = 5" 출력.
  1. processItem() 종료 (스택 영역)
  • stack: processItem() 메서드의 스택 프레임 제거.
  • "processItem end" 출력.
  1. initiateProcess() 종료 (스택 영역)
  • stack: initiateProcess() 메서드의 스택 프레임 제거.
  • "initiateProcess end" 출력.
  1. main() 종료 (스택 영역)
  • stack: main() 메서드의 스택 프레임 제거.
  • "main end" 출력.

5. static 변수

static 변수는 클래스 레벨에서 관리되며, 모든 인스턴스에서 공통으로 사용된다. 객체 생성과 상관없이 클래스명으로 접근할 수 있다.

public class Store {
    public static int totalItems = 0; // static 변수

    public Store() {
        totalItems++; // 객체 생성 시마다 증가
    }
}

이 코드에서 totalItems는 모든 Store 객체가 공유하는 값이며, 새로운 객체가 생성될 때마다 증가한다.


6. static 메서드

static 메서드는 객체를 생성하지 않고 클래스명으로 바로 호출할 수 있다.
주로 유틸리티 성격의 메서드에 사용된다.

public class MathHelper {
    public static int square(int number) {
        return number * number;
    }
}

public class Main {
    public static void main(String[] args) {
        int result = MathHelper.square(5);
        System.out.println("Square of 5: " + result);
    }
}

실행 결과:

Square of 5: 25

static 메서드는 인스턴스 생성 없이 바로 호출 가능하며, 프로그램 전체에서 공통적으로 사용되는 유틸리티 메서드에 적합하다.

profile
🫠

0개의 댓글