먼저 왜 언어를 공부할 때 실행 구조와 메모리를 이해하면 좋은 지 알아보고, 실행 과정, JVM의 구성 요소, 메모리 구조와 에제 코드에 대해 작성한다.
1. 왜 언어 실행 구조와 메모리 모델을 이해해야 할까?
돌아간다 신난다를 위해서는 사실 이론에 대한 공부는 딱히 하지 않아도 된다.
하지만 구현을 넘어 더 딥한 고민으로 퀄리티 있는 코드를 짜기 위해서는 동작 원리를 이해해야 한다.
언어에 대한 깊은 이해를 하고 코드를 짜면 좋은 점
효율적인 메모리 사용
- 메모리 사용 최적화 가능
- Garbage Collection의 작동 원리를 알면 메모리 누수 방지 가능(객체 참조 적시에 제거하는 등)
디버깅과 문제 해결 능력 향상
- NullPointerException, StackOverflowError, OutOfMemoryError와 같은 문제를 발생 원인부터 파악 가능
- ex: Stack에 메서드 호출 정보가 저장됨을 이해하면, 재귀 호출이 과도해지면 에러가 발생할 수 있음을 예측 가능
- NullPointerException, StackOverflowError, OutOfMemoryError와 같은 문제를 발생 원인부터 파악 가능
성능 최적화
- JVM의 실행 구조를 이해하면 불필요한 오버헤드를 줄이고 최적화된 코드 작성 가능
- ex: JIT(Just-In-Time) 컴파일러는 자주 실행되는 코드를 네이티브 코드로 변환하여 성능을 향상시키므로 성능에 민감한 부분에서는 반복적인 연산을 줄일 필요가 있음.
- JVM의 실행 구조를 이해하면 불필요한 오버헤드를 줄이고 최적화된 코드 작성 가능
멀티스레드 환경에서 안정적 코드 작성
- JVM 메모리 모델을 이해하면 멀티스레드 환경에서 발생하는 문제(ex: 경쟁 조건, 데드락)를 피할 수 있음
- ex: 메모리 동기화의 중요성을 이해하고, volatile 키워드나 synchronized 블록의 필요성 알 수 있음
- JVM 메모리 모델을 이해하면 멀티스레드 환경에서 발생하는 문제(ex: 경쟁 조건, 데드락)를 피할 수 있음
코드 설계 능력 향상
- 객체 생성과 생명주기를 고려하여 설계 가능
- 객체를 필요 이상으로 생성하지 않고 재사용(싱글톤 패턴 활용 등)
- 객체 생성과 생명주기를 고려하여 설계 가능
의도하지 않은 메모리 공유 문제 방지
- static 변수와 인스턴스 변수가 메모리에 저장되는 방식을 이해하면, 공유되는 데이터의 설계 명확히 가능
프레임워크와 라이브러리 사용 이해도 증가
- Spring, Hibernate와 같은 프레임워크는 내부적으로 JVM의 메모리 구조와 GC 동작을 활용.
- ex: Spring의 Bean Scope(Singleton, Prototype)을 활용할 때 객체가 메모리에서 어떻게 관리되는지 알면 적절한 스코프 설정 가능
- Spring, Hibernate와 같은 프레임워크는 내부적으로 JVM의 메모리 구조와 GC 동작을 활용.
안정성과 유지보수성 향상
- 코드 작성 시 메모리 구조를 고려하면 잠재적 성능 병목을 줄이고, 유지보수 비용 감소.
- ex: Immutable 객체를 활용하면 스레드 안전성을 높일 수 있음
이런 사실을 인지하고 코드를 짜는 것과 모르고 남들이 다 이렇게 짜니까 짜는 것은 처음에는 크게 차이가 나지 않을 수 있어도 시간이 지날수록 많은 차이를 보일 것이다. 나는 지금이라도 그 격차를 줄여보고자 자바의 동작 원리에 대해 확실히 알고 넘어가고자 한다.
- 코드 작성 시 메모리 구조를 고려하면 잠재적 성능 병목을 줄이고, 유지보수 비용 감소.
2. 자바의 실행 과정
2-1. 소스코드 작성(.java 파일)
- 개발자가 작성한 자바 코드
2-2. 컴파일(.class 파일)
- javac 컴파일러를 통해 바이트코드로 변환
- 운영체제나 하드웨어에 독립적인 형태로 변환됨
2-3. 실행(JVM)
- JVM이 바이트코드를 읽고, 인터프리터 및 JIT 컴파일러로 실행.
- JVM은 자바 프로그램의 플랫폼 독립성 보장
todo: (다이어그램 추가하기)
3. JVM 구성 요소
3-1. ClassLoader
- 클래스 파일을 읽고 메모리에 로드.
- 동적으로 필요한 클래스를 로드해주는 역할.
3-2. Execution Engine
- 바이트코드를 해석하고 실행.
- 인터프리터(순차 실행)와 JIT(자주 실행되는 코드 최적화)로 구성.
3-3. Runtime Data Area
- 프로그램 실행 중 데이터를 저장하는 메모리 영역. (Heap, Stack 등)
3-4. Garbage Collector(GC)
- 사용하지 않는 객체를 메모리에서 자동으로 제거.
todo: (설명, 그림 추가하기)
4. JVM의 메모리 구조
4-1. Method Area
- 클래스 정보, 상수, 메서드 코드 등 저장
4-2. Heap
- 객체가 저장되는 공간.(GC 관리)
4-3. Stack
- 메서드 호출과 지역 변수 저장
4-4. PC Register
- 현재 실행 중인 명령어의 주소 저장.
4-5. Native Method Stack
- 네이티브 코드(플랫폼 종속 코드) 실행 시 사용.
todo: (그림, 설명 추가)
5. 예제 코드
public Class Main {
public static void main(String[] args) {
int x = 10; // Stack에 저장
String str = "Hello"; // String Pool(Heap에 저장)
Object obj = new Object(); // Heap에 저장
}
}
6. 정리
- 요약
- 자바는 소스코드를 바이트 코드로 컴파일하고, JVM이 실행하는 구조.
- JVM은 ClassLoader, Execution Engine, Garbage Collector, 메모리 구조로 구성되어 안정성과 효율성을 제공
todo: GC 작동원리 + JIT컴파일러와 인터프리터 차이 정리하기
다음주 금요일 시험이므로 일단 큰 맥락만 정리했다. 이후 정리 추가 예정!
'개발 > Basics' 카테고리의 다른 글
[Java/Basics] 자바 기초 스터디 4주차: 예외처리와 스트림 (0) | 2025.02.12 |
---|---|
[Java/Basics] 자바 기초 스터디 3주차: 상속과 다형성 (0) | 2025.02.03 |
[Java/Basics] 자바 기초 스터디 2주차: 객체지향 프로그래밍(OOP) 기초 (1) | 2025.01.28 |
[Java/Basics] 자바 기초 스터디 (0) | 2025.01.18 |