자바 코드의 메모리 영역(스택&힙)

2024. 10. 29. 23:15·💻 Dev/Java & OOP

자바 프로그램에서 코드가 컴파일되어 JVM에서 실행되기까지 과정에서 JVM은 필요한 데이터들을 용도에 따라 나누어 관리한다.

 

JVM의 메모리 공간은 크게 Method 영역, Stack 영역, Heap 영역으로 구분되고 데이터 타입(자료형)에 따라 각 영역에 나눠서 할당된다.

 

 

 

메서드 영역(Method Area)

메서드 영역은 JVM이 시작될 때 생성되는 곳으로 클래스 변수(Static 변수), 생성자(constructor)와 메서드(method) 등이 저장되는 공간이다.

  • Static 영역이라고도 불리며 어느 곳에서나 접근이 가능하다.
  • 모든 스레드에서 공유되어 멀티 스레드 환경에서 동기화에 주의해야 한다.
  • 메서드 영역의 데이터는 프로그램이 종료될 때까지 메모리에 남아있다.
    그래서 프로그램이 종료될 때 까지 어디서든 사용이 가능하다.
  • 무분별하게 많이 저장할 경우 메모리 부족 현상이 일어날 수 있다.
public class Car {

    private static final int NAME_LENGTH_COND = 5;

    private final String name;
    private int position;

    public Car(final String name, final int position) {
            validateNameLength(name);
        this.name = name;
        this.position = position;
    }

    public void move() {
        position++;
    }

    private void validateNameLength(final String name) {
        if (name.length() > NAME_LENGTH_COND) {
            throw new IllegalArgumentException("이름은 5글자까지만 가능합니다.");
        }
    }
}

 

이 코드에서는 클래스 변수(NAME_LENGTH_COND), 생성자(Car), 메서드(move(), validateNameLength())가 메서드 영역에 저장된다.

 

 

스택(Stack)

스택 영역은 메서드 호출 시 생성되는 기본 자료형인 지역 변수와 매개 변수가 저장되는 영역이다.

  • 각 스레드마다 독자적인 스택 영역을 가진다.
  • 스택 프레임(Stack Frame) 단위로 메모리를 관리한다.
  • 메서드가 하나 호출될 때마다 스택 프레임이 생성되고 메서드가 끝나거나 예외가 터지면 제거된다.
  • 이 스택이 가득 찼을 때 발생하는 오류가 StackOverFlowError이다. (재귀 호출)

 

스택 프레임이란?

하나의 메서드에 필요한 메모리 덩어리를 묶어서 스택 프레임(Stack Frame)이라고 한다.
메서드를 호출하기 직전 스택 프레임을 스택영역에 생성한다.

 


위 코드의 Car 객체를 생성하고 move() 메서드를 실행한다면 3덩어리의 스택 프레임이 생성된다.

 

메서드가 호출될 때마다 생성되므로 Car 생성자 -> validateNameLength() -> move() 순서대로 쌓이고 메서드 실행이 끝나면 해당 스택프레임은 스택에서 제거된다.

 

name, position이 왜 저장돼?라고 생각할 수 있다. 그건 힙 스택 이후에 확인해 보자

 

힙(Heap)

힙 영역은 new 키워드를 통해 생성된 참조형 객체와 인스턴스 변수 그리고 배열이 저장된다.

  • 메서드 영역과 동일하게 모든 스레드에서 공유되는 곳이다.
  • 단, 힙 영역에 있는 객체들을 가리키는 참조를 위한 주소값은 스택에 포함된다.
  • 힙 영역은 스택 영역과 다르게 보관된 데이터가 호출이 끝나더라도 삭제되지 않고 유지된다.
  • 더 이상 참조하지 않는 객체 데이터는 가비지 컬렉터(GC)에 의해 제거된다.
public class Main {
    public static void main(String[] args) {
        Car car = new Car("kaki", 0);
        car.move();
    }
}

 

이 코드를 실행해 보자.

1. Car car = new Car("kaki", 0);

 

스택 영역에 생성자 메서드의 스택 프레임이 생성되고Car 객체에 대한 주소값을 가진다.
힙 영역에 Car 클래스의 인스턴스 변수, 값이 저장되고 스택 영역의 해당 주소값과 연결된다.

 

name과 position은 지역변수/매개변수가 아니라 인스턴스 변수인데 왜 스택에 저장되는가?

스택 영역의 name과 position은 실제 값이 아닌, 메서드의 매개변수와 참조가 잠시 저장되는 것이다.

public Car(final String name, final int position) {
            validateNameLength(name);
        this.name = name;
        this.position = position;
    }

 

즉, Car생성자 호출 시에, 생성자에 전달되는 매개변수 name과 position(즉, "CarName"과 0)은 생성자 호출 시 스택 영역에 저장되는 것이다.


name과 position은 매개변수로서 단순히 메서드 호출 동안에만 잠시 스택에 존재하는 것일 뿐이고 메서드 실행이 끝나면 스택에서 사라진다.

 

2. car.move();

 

생성자 호출이 끝났으니 Car 생성자 스택 프레임과 validateNameLength() 메서드 스택 프레임은 제거되고, mova() 메서드 스택 프레임이 추가된다.

여기서 this 라는 암묵적인 변수가 자동 생성되게 되는데, 이 this 변수는 자동으로 힙 영역에 있는 Car 객체를 가리키게 된다.
그래서 move() 메서드 안의 코드 position++이 동작하면 힙 영역에 있는 인스턴스 변수 position 값이 변하게 된다.

 

3. main() 메서드 종료

move() 메서드가 종료되고 main() 메서드 호출이 끝나면 main() 스택 프레임이 스택 영역에서 제거된다.

힙 영역의 Car 객체 데이터는 더 이상 참조하는 곳이 없을 때 GC에 의해 제거된다.

 

 

왜 각 종류의 변수들은 해당 메모리에 할당될까?

각 영역을 알아봐도 헷갈려서 따로 정리하게 됐다.

public class Calculator {
    int a = 1; //인스턴스 변수
    static int b = 3; //클래스 변수

    public static void main(String[] args) { //매개변수
        Calculator cal = new Calculator();
        int c = 3; //지역변수
    }
}

 

각 영역이 뭔진 알겠는데

왜 클래스 변수는 메서드 영역에 저장되고, 인스턴스 변수는 힙 영역에 저장되고, 매개변수/지역변수는 스택에 저장될까?

 

인스턴스 변수(a)가 힙 영역에 저장되는 이유

생성 시기
: new Calculator()로 새로운 Calculator 객체를 생성할 때 a라는 인스턴스 변수가 생성된다.

 

왜 힙에 저장되는가?
인스턴스 변수는 각 객체마다 고유한 값을 가지므로 객체가 생성될 때마다 독립적으로 생성되어야 한다.
힙은 객체가 메모리에 할당되어 더 이상 참조되지 않을 때까지 제거되지 않고 유지된다.
인스턴스 변수는 객체와 함께 힙 영역에 저장되어 해당 객체가 참조될 때마다 접근할 수 있어야 하기 때문이다.

 

클래스 변수 (b)가 메서드 영역에 저장되는 이유

생성 시기
: 클래스 변수는 Car 클래스가 처음 메모리에 로드될 때 한 번 생성된다.

 

왜 메서드 영역에 저장되는가?
클래스 변수는 모든 인스턴스가 공유하는 값이다 즉, 여러 객체가 생성되더라도 단 하나의 값을 유지한다.
메소드 영역은 프로그램 종료 시까지 유지되므로 클래스 변수의 값도 프로그램 종료 시까지 유지되어야 하기 때문이다.

 

매개변수 (args), 지역 변수 (c)가 스택 영역에 저장되는 이유

생성 시기
: 매개변수는 메서드가 호출될 때 생성된다.

 

왜 스택에 저장되는가?
매개변수와 지역변수는 메서드나 코드 블록 내에서만 사용되고, 해당 코드 블록이 끝나면 더 이상 참조되지 않는 임시 데이터입니다.
스택은 메소드 호출 시 생성되는 지역 데이터의 임시 저장을 위해 사용되고, 두 변수의 데이터는 메서드가 끝나면 필요 없어지므로 스택에서 관리된다.

 

 

 

참고
JVM 메모리 구조 파헤쳐 보기 (Static, Stack, Heap)
그림으로 보는 자바 코드의 메모리 영역(스택 & 힙)

저작자표시 비영리 (새창열림)

'💻 Dev > Java & OOP' 카테고리의 다른 글

String Constant Pool, feat. Runtime Constant Pool  (0) 2024.11.02
BigDecimal이란?  (0) 2024.10.30
Immutable(불변성), StringBuffer와 StringBuilder  (0) 2024.10.29
JVM 구조와 동작 과정  (0) 2024.10.29
예외(Checked Exception, Unchecked Exception)  (0) 2024.10.26
interface와 abstract(추상) 클래스  (0) 2024.10.25
'💻 Dev/Java & OOP' 카테고리의 다른 글
  • BigDecimal이란?
  • Immutable(불변성), StringBuffer와 StringBuilder
  • JVM 구조와 동작 과정
  • 예외(Checked Exception, Unchecked Exception)
현주먹
현주먹
대구 불주먹 출신 현주먹의 개발.log
  • 현주먹
    현주먹의 개발로그
    현주먹
  • 전체
    오늘
    어제
    • 전체글 (179)
      • 👶🏻 CS (15)
        • Operating System (7)
        • DB (5)
        • Data Structure (2)
        • Software Engineering (1)
      • 💻 Dev (54)
        • Java & OOP (24)
        • Spring (4)
        • DB&JPA (6)
        • Test Code (1)
        • JSP & Servlet (13)
        • Etc (6)
      • 💡 Algorithm (25)
        • 인프런 (9)
        • 백준 (16)
      • 🛠 DevOps & Tool (11)
        • Linux (4)
        • AWS (1)
        • Git (2)
        • Etc (4)
      • 📝 끄적끄적 (74)
        • 후기 및 회고 (11)
        • TDD, 클린 코드 with Java 17기 (3)
        • F-Lab (23)
        • 🖥️ 자바의 정석 (11)
        • 📖 Clean Code (3)
        • 항해99 코테 스터디 (11)
        • 📖 가상 면접 사례로 배우는 대규모 시스템 설계 .. (11)
  • 블로그 메뉴

    • 🐈‍⬛ GitHub
    • TIL repository
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 태그

    인프런 특정문자뒤집기
    til
    NextSTEP
    로또 미션
    자바의신절판
    2025스프링캠프
    개구리책
    개발자멘토링
    F-Lab
    JPA
    에프랩
    C
    객체지향
    백준
    ==와 equals()
    에프랩 후기
    jsp 2.3 웹 프로그래밍: 기초부터 중급까지
    코테스터디
    f-lab 후기
    99클럽
    TDD 클린 코드 with Java
    개발자취업
    항해99
    jsp
    자바의정석
    코딩테스트준비
    오블완
    오라클
    티스토리챌린지
    데브클럽
  • hELLO· Designed By정상우.v4.10.2
현주먹
자바 코드의 메모리 영역(스택&힙)
상단으로

티스토리툴바