본문 바로가기
Java

Java | 메모리 구조 + static vs 인스턴스 종합 정리

by Sseul.dev 2025. 10. 4.

JVM 메모리 구조 전체 그림

┌──────────────────────────────────────────────────────────┐
│                     JVM Memory                           │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  ┌──────────────────────────────────────────────────┐    │
│  │            Method Area (Metaspace)               │    │
│  │                                                  │    │
│  │  • 클래스 메타데이터                                  │   │
│  │  • static 변수들                                   │   │
│  │  • static 메서드 코드                               │   │
│  │  • 상수 풀 (Constant Pool)                         │   │
│  │                                                  │   │
│  └──────────────────────────────────────────────────┘   │
│                           ↕                             │
│  ┌──────────────────────────────────────────────────┐   │
│  │                    Heap                          │   │
│  │                                                  │   │
│  │  • new로 생성한 모든 객체                             │   │
│  │  • 인스턴스 변수들                                   │   │
│  │  • 배열                                           │   │
│  │                                                  │   │
│  │  [객체1]  [객체2]  [객체3]  ...                     │   │
│  │                                                  │   │
│  └──────────────────────────────────────────────────┘   │
│                           ↕                             │
│  ┌──────────────────────────────────────────────────┐   │
│  │                    Stack                         │   │
│  │                                                  │   │
│  │  • 메서드 호출 정보                                  │   │
│  │  • 지역 변수                                       │   │
│  │  • 매개변수                                        │   │
│  │  • 리턴 값                                         │   │
│  │                                                  │   │
│  └──────────────────────────────────────────────────┘   │
│                                                         │
└─────────────────────────────────────────────────────────┘

실제 코드로 메모리 동작 이해

java
public class BankAccount {
    // 인스턴스 변수 - Heap에 저장
    private String accountHolder;
    private double balance;
    
    // static 변수 - Method Area에 저장
    private static int totalAccounts = 0;
    private static double interestRate = 0.02;
    
    // 생성자
    public BankAccount(String holder, double initial) {
        this.accountHolder = holder;
        this.balance = initial;
        totalAccounts++;
    }
    
    // 인스턴스 메서드
    public void deposit(double amount) {
        balance += amount;
    }
    
    // static 메서드  
    public static void setInterestRate(double rate) {
        interestRate = rate;
    }
}

코드 실행 시 메모리 변화

Step 1: 프로그램 시작

Method Area:
┌────────────────────┐
│ BankAccount.class  │
│ totalAccounts: 0   │
│ interestRate: 0.02 │
└────────────────────┘

Heap: (비어있음)

Stack: 
┌────────────────────┐
│ main() 시작         │
└────────────────────┘

Step 2: 첫 번째 계좌 생성

java
BankAccount acc1 = new BankAccount("김철수", 1000000);
 
Method Area:
┌────────────────────┐
│ totalAccounts: 1   │ ← 증가!
│ interestRate: 0.02 │
└────────────────────┘

Heap:
┌────────────────────┐
│ acc1 객체           │
│ holder: "김철수"     │
│ balance: 1000000   │
└────────────────────┘

Stack:
┌────────────────────┐
│ acc1 = @주소1       │ ← Heap 객체 가리킴
└────────────────────┘

Step 3: 두 번째 계좌 생성

java
BankAccount acc2 = new BankAccount("박영희", 2000000);
 
 
Method Area:
┌────────────────────┐
│ totalAccounts: 2   │ ← 또 증가!
│ interestRate: 0.02 │
└────────────────────┘
        ↑ 공유 ↑
        
Heap:
┌────────────────────┐  ┌────────────────────┐
│ acc1 객체           │  │ acc2 객체           │
│ holder: "김철수"     │  │ holder: "박영희"    │
│ balance: 1000000   │  │ balance: 2000000   │
└────────────────────┘  └────────────────────┘

Stack:
┌────────────────────┐
│ acc1 = @주소1       │
│ acc2 = @주소2       │
└────────────────────┘

Step 4: static 메서드 호출

java
BankAccount.setInterestRate(0.03);  // 이자율 변경
 
Method Area:
┌────────────────────┐
│ totalAccounts: 2   │
│ interestRate: 0.03 │ ← 변경! (모든 계좌 영향)
└────────────────────┘

⚠️ static 메서드가 인스턴스 변수 접근 못하는 이유

java
public static void wrongMethod() {
    System.out.println(balance);  // 에러!
}

 

시각적 설명:

BankAccount.wrongMethod() 호출 시:

Method Area에서 실행
     ↓
"balance를 출력하라고?"
     ↓
Heap을 봐야 하는데...
     ↓
acc1의 balance? acc2의 balance?
     ↓
알 수 없음! → 컴파일 에러

메모리 영역별 특징

영역 저장되는 것 생성 시점 소멸 시점
Method Area static 변수/메서드, 클래스 정보 클래스 로딩 시 프로그램 종료
Heap 객체, 인스턴스 변수, 배열 new 실행 시 GC가 수거
Stack 지역변수, 매개변수, 메서드 호출 메서드 호출 시 메서드 종료

핵심 정리

접근 규칙

인스턴스 메서드 → 모든 영역 접근 가능
static 메서드 → Method Area만 접근 가능

실용적 비유

Method Area = 회사 게시판 (모두가 봄)
Heap = 각자의 책상 (개인 소유)  
Stack = 임시 메모장 (작업 중에만 사용)
 

'Java' 카테고리의 다른 글

Java | 생성자 체인(Constructor Chaining)  (0) 2025.10.11
Java | Hiding  (0) 2025.10.04
Java | 정적 변수 vs 정적 메서드  (2) 2025.10.04
Java | static vs 인스턴스 변수 차이점  (0) 2025.10.04
Java | 업캐스팅과 다운캐스팅  (0) 2025.10.02