Java는 메모리 관리를 자동으로 수행하는 가비지 컬렉터(Garbage Collector, GC) 를 제공하여 개발자가 직접 메모리를 해제하지 않아도 됩니다. 하지만 효율적인 Java 애플리케이션을 개발하기 위해서는 Java의 메모리 구조를 이해하는 것이 중요합니다.
이번 글에서는 Java의 메모리 영역과 그 동작 방식을 자세히 살펴보겠습니다.
1. Java 메모리 구조 개요
Java 애플리케이션이 실행될 때, JVM(Java Virtual Machine) 은 여러 개의 메모리 영역을 관리합니다. JVM 메모리는 크게 Method Area, Heap, Stack, PC Register, Native Method Stack 으로 나뉩니다.
🔹 Java 메모리 영역 구성
메모리 영역 | 설명 |
Method Area (메서드 영역, 클래스 영역) | 클래스 정보, static 변수, 메서드 코드 저장 |
Heap (힙 영역) | 객체 및 인스턴스 변수 저장 |
Stack (스택 영역) | 메서드 호출 시 지역 변수 및 참조 변수 저장 |
PC Register (PC 레지스터) | 현재 실행 중인 명령어 주소 저장 |
Native Method Stack (네이티브 메서드 스택) | JNI(Java Native Interface) 실행 시 사용 |
2. 메모리 영역 상세 분석
각 영역이 어떤 역할을 하며, 어떻게 동작하는지 살펴보겠습니다.
1) Method Area (메서드 영역)
"클래스 정보, static 변수, 메서드 코드가 저장되는 영역"
- JVM이 로드한 클래스의 메타데이터(Class Metadata) 저장
- static 변수와 상수(Constant Pool) 저장
- 메서드 코드(바이트코드)와 JIT(Just-In-Time) 컴파일된 코드 저장
- JVM이 종료될 때까지 유지되는 데이터 포함
✅ 예제 코드
class Example {
static int staticVariable = 100; // 메서드 영역에 저장됨
}
➡️ staticVariable은 Method Area에 저장됩니다.
2) Heap (힙 영역)
"객체(인스턴스)와 인스턴스 변수가 저장되는 영역"
- new 키워드를 통해 생성된 객체와 배열이 저장됨
- GC(Garbage Collector) 가 주기적으로 사용하지 않는 객체를 제거
- Young Generation, Old Generation(또는 Tenured), Permanent Generation(또는 Metaspace) 로 나뉨
✅ 예제 코드
class Person {
String name; // Heap에 저장됨
int age; // Heap에 저장됨
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("Alice", 25); // Heap에 저장됨
}
}
➡️ new Person("Alice", 25) 을 호출하면 힙 영역에 Person 객체가 생성됩니다.
3) Stack (스택 영역)
"메서드 실행 시 생성되는 지역 변수 및 참조 변수가 저장되는 영역"
- 각 쓰레드(Thread) 별로 독립적인 Stack을 가짐
- 메서드 호출 시 프레임(Call Stack Frame)이 생성되고, 종료되면 제거됨
- 지역 변수 및 참조 변수가 저장됨
✅ 예제 코드
public class Main {
public static void main(String[] args) {
int x = 10; // Stack에 저장
int y = 20; // Stack에 저장
Person p = new Person("Alice", 25); // p 변수(참조값)는 Stack에, 객체는 Heap에 저장됨
}
}
➡️ x, y, p는 Stack 영역에 저장되며, p가 참조하는 객체는 Heap 영역에 저장됩니다.
4) PC Register (PC 레지스터)
"현재 실행 중인 JVM 명령어의 주소를 저장하는 영역"
- 각 쓰레드별로 하나의 PC Register를 가짐
- JVM이 실행할 현재 바이트코드 명령어 주소를 저장
- 네이티브 코드(Java가 아닌 언어) 실행 시는 사용되지 않음
✅ 동작 방식
public class Main {
public static void main(String[] args) {
int a = add(5, 10);
}
public static int add(int x, int y) {
return x + y;
}
}
➡️ add() 메서드를 실행할 때, PC Register에는 add() 메서드의 현재 실행 위치가 저장됩니다.
5) Native Method Stack (네이티브 메서드 스택)
"JNI(Java Native Interface)로 호출된 네이티브 코드(C, C++) 실행 시 사용"
- JVM이 아닌 네이티브 코드(C, C++) 실행을 위한 공간
- OS 및 네이티브 라이브러리와의 연동을 위해 사용됨
✅ JNI 예제 코드
public class Main {
static {
System.loadLibrary("nativeLibrary"); // C/C++ 라이브러리 로드
}
public native void nativeMethod(); // 네이티브 메서드 선언
public static void main(String[] args) {
new Main().nativeMethod(); // 네이티브 메서드 실행 (Native Stack 사용)
}
}
➡️ nativeMethod() 실행 시 Native Method Stack이 사용됩니다.
3. Java 메모리 관리 및 GC (Garbage Collection)
🔹 JVM Heap 영역의 구조
JVM의 Heap 영역은 GC(Garbage Collector) 에 의해 관리됩니다.
영역 | 설명 |
Young Generation | 새롭게 생성된 객체가 저장됨 (Eden + Survivor) |
Old Generation | 오랫동안 참조된 객체가 저장됨 |
Metaspace (Java 8 이후) | 클래스 메타데이터 저장 |
🔹 가비지 컬렉션의 과정
- Young Generation (Minor GC) : Eden 영역이 가득 차면 사용되지 않는 객체 제거
- Old Generation (Major GC, Full GC) : 오래된 객체를 대상으로 GC 실행
- Finalization 및 메모리 해제 : 객체의 finalize() 호출 후 제거됨
✅ GC 로그 활성화
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log -jar app.jar
➡️ GC 로그를 출력하여 메모리 사용량을 모니터링할 수 있습니다.
4. 메모리 최적화 방법
- 객체 재사용 (Object Pool, Singleton) : 불필요한 객체 생성을 줄임
- 컬렉션 초기 크기 설정 : ArrayList, HashMap 등의 초기 크기를 적절히 설정
- WeakReference 사용 : 캐시 데이터는 WeakReference를 사용하여 GC 대상이 되도록 설정
- GC 튜닝 : -Xms, -Xmx 옵션으로 힙 크기 조정
5. 결론
Java의 메모리 영역을 이해하면 효율적인 메모리 관리와 성능 최적화가 가능합니다. 특히 GC 튜닝 및 메모리 프로파일링을 통해 메모리 누수를 방지하고 애플리케이션의 안정성을 높일 수 있습니다.
✅ 핵심 정리
- Method Area: 클래스 정보, static 변수 저장
- Heap: 객체 저장 (GC 대상)
- Stack: 메서드 호출 시 지역 변수 저장
- PC Register: 현재 실행 중인 명령어 위치 저장
- Native Stack: JNI 메서드 실행 시 사용
효율적인 Java 애플리케이션 개발을 위해 메모리 구조를 이해하고 최적화하는 습관을 가지세요! 🚀
'백엔드' 카테고리의 다른 글
객체지향 설계 원칙 (SOLID) 개념과 적용 방법 (0) | 2025.02.17 |
---|---|
Java의 Error와 Exception 차이점 (1) | 2025.02.15 |
[자바/JAVA] 객체는 뭐로 만들어? Class, Interface, Record? (1) | 2025.02.12 |
[자바/JAVA] DAO, DTO, VO, Entity의 차이점과 역할 (1) | 2025.02.11 |
[DB] 관계형(RDB) vs 비관계형(NoSQL) 데이터베이스 비교 (1) | 2025.02.10 |