티스토리 뷰

자바 아이콘

 

들어가기전 아주 간단 용어 설명

 

  • 컴파일 : 프로그래밍 언어로 작성한 소스코드를 중간언어인 바이트(바이너리)코드로 변환하는 작업
  • 바이트(바이너리) 코드 : 프로그램 실행을 위한 0과 1로 이루어진 표현법
  • JVM : Java Virtual Machine의 약자로 자바 가상 머신으로 물리적으로 존재하지 않은 가상 검퓨터
  • JVM 실행 : JVM 프로세스가 운영체제에서 생성되고, Java 어플리케이션을 실행할 준비 완료

 

 

 

 

왜 JVM이 등장 했을까?

문제) 각 운영체제에 맞춰 컴파일하는 불편함

  • Window로 C언어를 컴파일 한 것을 Mac 또는 Linux는 해당 컴파일 소스파일을 해석을 못하는 문제가 발생하였습니다.
  • 즉, 배포된 환경의 운영체제와 아키텍처를 맞춰 컴파일했어야 했습니다.

 

C언어 컴파일 했던 상황
그림1) 과거엔 C언어는 OS에 맞춰 컴파일 ㅠㅠ

해결) 혜성같이 등장

  • 각 운영체제에 다운 받은 JVM이 컴파일하여 생긴 바이트 코드를 해당 운영체제에 맞게 해석하여 실행해줍니다.
  • 즉, JVM은 각 운영체제에 독립적으로 애플리케이션을 실행하게 할 수 있다는 것입니다. 

JVM을 이용해 자바소스코드 실행
그림2) JVM이 바이트코드를 각 운영체제에 맞춰 실행

 

 

 

 

JVM 아키텍처 구조 및 각 간단 설명

 

JVM 아키텍처
그림3) JVM 아키텍처

Class Loader (클래스 로더)

  • JVM이 실행될 때, 가장 먼저 클래스 로더가 동작하여 컴파일된 .class 파일(바이트 코드)을 메모리(Runtime Data Area)로 로드하는 역할

Runtime Data Area (런타임 데이터 영역)

  • JVM이 실행될 때 사용하는 메모리 공간
  • Method Area (메서드 영역) 클래스 메타데이터인 클래스명, 메서드, 필드, 변수 등 저장
  • Heap (힙 영역) 프로그램을 실행하면서 생성한 모든 객체 인스턴스를 Heap에 저장
  • Java Stack (스택 영역) → 메서드 호출 시 각 스레드마다 독립적인 스택 프레임을 저장
  • PC Register (PC 레지스터) 현재 실행 중인 메서드 명령어 주소 저장
  • Native Method Stack (네이티브 메서드 스택) JNI(Java Native Interface)를 통한 네이티브 코드 실행

Execution Engine (실행 엔진)

  • 바이트코드를 실행하는데 처음엔 인터프리팅 방식으로 실행하다가, 특정 코드가 반복 실행되면 JIT 컴파일러가 네이티브 코드로 변환하여 속도를 향상시키는 역할
  • 인터프리터 바이트 코드를 한 줄 씩 해석하면서 실행
  • JIT 컴파일러 반복적으로 실행되는 코드를 기계어로 변환하여 최적화
  • Garbage Collector (GC) → Heap 영역에서 불필요한 객체를 정리하는 역할을 수행

Java Native Interface (JNI, 네이티브 인터페이스)

  • Java에서 C/C++같은 네이티브 코드를 실행할 수 있도록 지원하는 역할
  • 즉, 런타임 데이터 영역의 네이티브 메서드 스택에서 네이티브 코드를 실행할 수 있게 지원

Native Method Libraries (네이티브 메서드 라이브러리)

  • JNI를 통해 호출되는 네이티브 라이브러리 (C, C++ 코드)

 

 

 

 

JVM이 실행되는 과정

 

대략적인 흐름만 설명하였고, 자세한건 이후 아래 글에 설명하겠습니다.

 

  1. 개발자가 .java 파일에 Java 소스 코드 작성합니다.
  2. 컴파일 하어 .class 파일인 바이트 코드가 생성됩니다.
  3. JVM이 실행될 때 가장먼저 클래스 로더가 동작하여 .class파일을 메모리에 로드합니다.
  4. 컴파일된 바이트코드를 실행하여  인터프리터 방식 및 JIT 컴파일러로 실행합니다.
  5. 프로그램 실행 중에 힙, 스택, 메서드 영역 등 활용하여 메모리 관리를 합니다.
  6. 실행 중에 더 이상 사용되지 않는 객체를 가비지 컬렉션이 정리합니다.
  7. 프로그램 종료했을 때 JVM은 모든 메모리 해제하여 종료합니다.

Java 프로그램 실행 순서
그림4) Java 프로그램 실행 순서

 

 

 

Class Loader (클래스 로더)

 

위에서 간단 설명으로 컴파일된 바이트코드를 메모리에 로드하는 역할을 한다고 하였습니다.

클래스 로딩과정무엇을 로딩할까? 정도만 알아보도록 하겠습니다.

 

1. 클래스 로딩 (Loading)

  • 바이트 코드를 가져와서 JVM에 로드합니다.
  • ClassLoader 라는 클래스 로딩 담당 객체에 의해 이루어집니다.
    즉, 클래스 파일이 저장된 경로에서 클래스를 찾아 JVM에 로드합니다.

2. 클래스 링크 (Linking)

  • 바이트 코드를 사용하기 위해 검증하는 과정입니다.
  • [검증] 클래스 파일이 유효한지 확인하고 JVM이 처리할 수 있는 형식인지 검사합니다.
  • [준비] 클래스 static 변수들이 기본 값으로 초기화됩니다.
    즉, 변수들이 메모리에 배치되고 기본 값으로 할당됩니다.
  • [분석] 클래스에서 참조하는 다른 클래스나 메소드, 필드를 실제 메모리 주소로 변환하는 과정입니다.

3. 클래스 초기화 (Initialization)

  • 클래스 변수들을 할당한 값으로 재할당합니다.
  • static 블록이 있다면 해당 블록이 실행됩니다.
  • 해당 초기화는 클래스가 처음 사용될 때 또는 Class.forName()을 통해 명시적으로 로드할 때 발생합니다.

 

어떤 클래스를 로딩을 어떤 순서로?

  1. Bootstrap : java.lang 패키지 등 기본적인 핵심 Java 클래스를 로드 (기본클래스)
  2. Extension : lib/ext 디렉토리에 있는 확장 클래스를 로드 (라이브러리 클래스)
  3. Application : 사용자가 작성한 클래스 로드 (커스텀 클래스)

클래스 로더 계층
그림5) 클래스 로더 계층

 

 

 

 

Execution Engine (실행 엔진)

 

위에서 간단 설명으로 컴파일된 바이트 코드를 실행하는 역할을 한다고 하였습니다.

실행할 때 2가지의 방법으로 실행됩니다.

Interpreter (인터프리터)

  • 바이트 코드를 한 줄 씩 해석하여 실행합니다.
  • 바로 실행이 가능하기 때문에 빠른 시작이 장점이며, 한 줄 씩 해석해야하기 때문에 실행속도가 느립니다.

Just-In-Time (JIT 컴파일러)

  • 반복적으로 실행되는 코드를 기계어(네이티브 코드)로 변환하여 최적화 합니다.

 

결론으론, JVM은 처음에는 인터프리터 방식으로 실행하다가, 특정 코드가 반복 실행되면 JIT 컴파일러가 네이티브 코드로 변환하여 실행속도를 향상시킵니다.

Garbage Collector (GC, 가비지 컬렉터)

  • Heap영역에서만 동작하며 사용하지 않는 객체를 자동으로 정리해줍니다.
  • Minor GC(Young Generation), Major GC(Old Generation) 으로 동작됩니다.

 

 

 

 

Runtime Data Area (런타임 영역 데이터)

 

위에서 간단하게 설명했지만 JVM이 실행할 때 사용하는 메모리 공간이라고 하였습니다.

Method Area (메소드 영역)

  • 모든 스레드가 공유합니다.
  • 클래스 로더가 바이트 코드를 메모리에 로드한다고 하였는데 이 곳에 클래스의 메타데이터들을 저장합니다.

Heap (힙 영역)

  • 모든 스레드가 공유합니다.
  • 프로그램을 실행하면서 생성한 모든 객체 인스턴스를 저장합니다.

메소드영역과 힙영역 시각화
그림6) 메소드영역과 힙영역 시각화

PC Register (PC 레지스터)

  • 각 스레드마다 독립적으로 존재합니다.
  • 각 스레드의 실행 중인 바이트 코드(명령어)의 주소를 저장합니다.
  • 메서드 안에서 몇 번째 줄을 실행해야하는지 저장합니다.

Java Stack (스택 영역)

  • 자바 스택은 각 스레드 별로 1개만 존재하고, 스택 프레임은 메서드가 호출될 때마다 생성됩니다.
  • 각 스레드별 스택 프레임을 저장합니다.
  • 스택 프레임
    • 메서드가 호출될 때마다 새로 생겨 스택에 추가(push) 됩니다.
    • 메서드 실행이 끝나면 스택에서 제거(pop) 됩니다.
    • 스택 프레임은 지역변수(Local variables array), 메서드 내 연산 작업 공간(Operand stack), Frame Data를 갖습니다.
    • Frame Data는 Constant Pool, 이전 스택 프레임에 대한 정보, 현재 메서드가 속한 클래스/객체에 대한 참조 등의 정보를 갖는다.

Native Method Stack (네이티브 메서드 스택)

  • Java Bytecode가 아닌 다른 언어(C, C++)로 작성된 코드실행되는 메서드의 스택을 관리하는 영역입니다.
  • JNI (Java Native Interface)를 통해 호출된 네이티브 코드의 스택 프레임을 저장합니다.
  • 가끔 성능 향상을 목적으로 다른 컴파일 언어로 작성한게 있다고 합니다.

각 스레드 별 스택 저장 시각화
그림7) 각 스레드 별 스택 저장 시각화

 

 

 

 

실무 꿀팁

OutOfMemoryError가 발생하면 어떻게 할것인가?

  • Java heap space : Heap 메모리 부족 (대부분)
    ⇒ 원인 : 객체 과다 생성, 지속적인 메모리 누수, 일시적인 과도한 요청
    ⇒ 해결 방법 : 객체 수명 관리하기, 불필요한 객체 생성 줄이기
  • Metaspace : 클래스 메타데이터 공간 부족 (클래스 동적 로드가 많을 때)
    ⇒ 원인 : 동적 클래스 로딩 과다 (라이브러리가 class를 양산하고 있을 수도 있다)
    ⇒ 해결 방법 : 라이브러리가 과도하게 프록시 클래스 만드는 구조인지 점검
  • GC overhead limit exceeded : GC가 너무 자주 돌아서 성능이 심각하게 저하된 경우
    ⇒ 원인 : GC 반복 과부하, GC가 메모리를 정리하는데 너무 많은 시간과 반복적 실패를 했을 경우
    ⇒ 원인 : JVM GC를 수행하는 시간의 98%를 소비했지만 Heap 메모리의 2% 미만으로 복구되는 경우
    ⇒ 해결 방법 : GC 로그 통해 어떤 영역에서 문제인지 확인
    ⇒ 해결 방법 : DTO 필드 최소화, Jackson/Gson 등 직렬화 라이브러리 튜닝, ThreadLocal 객체 누수 여부 확인
  • Direct buffer memory : NIO direct buffer 메모리 부족
  • unable to create new native thread : OS 레벨에서 스레드 생성 불가
    ⇒ 원인 : OS 스레드 리소스 부족
    ⇒ 해결 방안 : 스레드 리소스를 늘린다. 리눅스OS면 ulimit -u 로 제한을 푼다

 

스레드 풀을 크게하면 왜 OutOfMemory가 발생할 수 있을까?

  • 스택 오버헤드 (OutOfMemoryError: unable to create new native thread)
    ⇒ JVM이 운영체제로부터 새로운 스레드를 생성하려고 할 때 OS가 더이상 메모리를 생성, 할당할 수 없을 때 발생한다.
  • 힙 메모리 부족 (OutOfMemoryError: Java heap space)
    ⇒ 작업 큐에 쌓이는 객체가 많아져서 힙메로리 초과가 발생한다.
  • GC 오버헤드 (OutOfMemoryError: GC overhead limit exceeded)
    ⇒ 너무 많은 스레드가 발생하면 GC가 계속 발생하여 CPU사용률이 높아져서 애플리케이션이 멈추는 문제가 발생한다.

 

 

 

 

참조 문서

 

https://www.artima.com/insidejvm/ed2/jvm2.html

 

Java Virtual Machine's Internal Architecture

Chapter 5 of Inside the Java Virtual Machine The Java Virtual Machine by Bill Venners <<  Page 2 of 13  >> Advertisement The Architecture of the Java Virtual Machine In the Java virtual machine specification, the behavior of a virtual machine instance

www.artima.com

 

 

감사합니다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함