JVM에 대한 이해와 JVM 구조 살펴보기

JVM 이란?

JVM에 대해 얼만큼 알고 있는가? 그저 개발자는 코딩만 잘하면 되지, JVM까지 알아야해? 라는 생각이 들수는 있다.(나만 그렇게 생각하는지는 모르겠다…) 하지만 JVM이 메모리를 관리하기에 JVM에 대한 이해를 하지 않고 코드를 작성하면 메모리 누수가 발생해 OutOfMemoryException이 발생할 수 있다. 또한 메모리 관리와 GC 튜닝을 통해 한정된 메모리를 효율적으로 관리하여 최고의 성능을 내기 위해 JVM에 대해 학습하는것도 있다.
먼저 JVM의 특징부터 알아보자.

JVM 특징

  • Java와 OS사이에서 중개자 역할
  • 특정 플랫폼에 종속적이다.
  • JVM은 자바 바이트 코드(.class 파일)를 OS에 특화된 코드로 변환(인터프리터와 JIT 컴파일러)하여 실행한다.
  • JVM은 바이트 코드를 실행하는 표준(JVM 자체는 표준)이자 구현체(특정 밴더가 구현한 JVM)이다.
    • JVM 특정 벤더 : 오라클, 아마존, Azul …
  • 컴퓨터 아키텍처 인털 x86 이나 ARM과 같은 하드웨어는 레지스터 기반으로 동작하는데에 비해, JVM은 스택기반이다.
  • 프로그램이 실행되는 도중에도 OS로 부터 동적으로 메모리 할당을 받아 관리한다.(Garbage Collection)
  • JVM을 기반으로 하는 언어: 클로저, 그루비, JRuby, Jython, Kotlin, Scala …

JDK 구조

JDK Structure

  • JRE(Java Runtime Enviroment): JVM + 라이브러리
    • 자바 애플리케이션을 실행할 수 있도록 구성된 배포판.
    • JVM과 핵심 라이브러리 및 자바 런타임 환경에서 사용하는 프로퍼티 세팅이나 리소스 파일을 가지고 있다.
    • 개발 관련 도구는 포함하지 않는다. (개발 관련 도구는 JDK에서 제공)
    • 오라클은 자바 11부터 JDK만 제공. JRE를 따로 제공하지 않는다.
  • JDK(Java Development Kit): JRE + 개발 툴
    • JRE + 개발에 필요한 툴
    • 소스 코드를 작성할 때 사용하는 자바 언어는 플랫폼에 독립적
    • Write Once, Run Anywhere
    • JDK에 들어 있는 자바 컴파일러(javac)를 사용하여 바이트코드(.class 파일)로 컴파일 할 수 있다.

JVM 구조

JVM Structure

  • 클래스 로더 시스템 JVM Class Loader
    • .class 에서 바이트코드를 읽고 메모리에 저장. 로딩 -> 링크 -> 초기화 순으로 진행.
    • 로딩(Loading): 클래스를 읽어오는 과정
      • Bootstrap: JAVA_HOME\lib에 있는 코어 자바 API를 제공한다. 최상위 우선순위를 가진 클래스 로더
      • Extention: JAVA_HOME\lib\ext 폴더 또는 java.ext.dirs 시스템 변수에 해당하는 위치에 있는 클래스를 읽는다.
      • Application: 애플리케이션 클래스패스(애플리케이션 실행할 때 주는 -classpath 옵션 또는 java.class.path 환경 변수의 값에 해당하는 위치에서 클래스를 읽는다.
    • 링크(Linking): 레퍼런스를 연결하는 과정
      • Verify: .class 파일 형식이 유효한지 체크한다.
      • Prepare: 클래스 변수(static 변수)와 기본값에 필요한 메모리.
      • Resolve: 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체.
    • 초기화(Initialization): static 초기화 및 변수에 할당.
  • 메모리 - Runtime Data Area Runtime Data Area
    • 메서드(Method): 클래스 수준의 정보(클래스 이름, 부모 클래스 이름, 메서드, 변수) 저장 한다.(공유 자원)
    • 힙(Heap): new 연산자를 통해 동적 할당된 객체를 저장한다.(공유 자원) GC(Garbage Collection)에 의해 관리 된다.
    • 스택(Stack): 쓰레드 마다 런타임 스택을 만들고, 그 안에 메서드 호출을 스택 프레임이라 부르는 블럭으로 쌓는다. 쓰레드가 종료되면 런타임 스택도 사라진다. LIFO 방식의 메모리.
    • PC(Program Counter) 레지스터: 쓰레드 마다 쓰레드 내 현재 실행할 Instruction의 위치를 가리키는 포인터가 생성된다.
    • 네이티브 메서드 스택(Native Method Stack): Java가 아닌 다른 언어 코드가 저장 되는 공간이며, Byte Code가 아닌 언어를 Byte Code로 전환하여 저장한다.
  • 실행 엔진
    • 인터프리터(Interpreter): 바이트 코드를 한줄씩 실행
    • JIT 컴파일러: 인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면 JIT 컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꿔둔다. 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다.
    • GC(Garbage Collection): 더 이상 참조되지 않는 객체를 모아서 정리한다.
  • JNI(Java Native Interface)
  • 네이티브 메서드 라이브러리
    • C, C++ 로 작성 된 라이브러리

그 외

JVM에 관련하여 우아한 Tech 유튜브 영상에서 잘 설명해주고 있어 해당 영상을 통해 부족한 부분을 채워줄 수 있을거라 생각된다.



참조

 Date: January 12, 2021
 Tags:  Java JVM

Previous
⏪ 자바 Generic은 무엇이며 어떻게 사용하는가

Next
Devflix 프로젝트 후기 ⏩