JVM

who_am_i·2021년 4월 27일
0

자바

목록 보기
1/1
post-thumbnail

1. 왜 필요할까?

  • c와 c++의 문제점

    C와 C++의 경우 컴파일 플랫폼과 타겟 플랫폼이 다를 경우 프로그램이 동작하지 않을 수 있다. 여기서 환경이란 운영체제 + CPU 아키택처를 말한다.
    이를 해결하기 위해 타겟 플랫폼에 맞춰 컴파일 해야되는데, 이것을 크로스 컴파일이라고 한다.

  • JVM 으로 문제를 해결

    후에 설명하겠지만 자바 바이트코드는 타겟 플랫폼에 상관 없이 JVM 위에서 동작한다.
    즉 JVM이 타겟 플랙폼에 의존하여 대신해주는 것이다.

    WORA

    • Write Once, Run Anywhere (JVM이 있는 장착된 어떤 장비에서도 실행될 수 있다는 뜻)
      -썬 마이크로시스템즈에 의해 만들어진 자바의 크로스/플랫폼에 의한 이익을 표현하기 위한 표어

    즉 자바는 JVM이 있는 모든 플랫폼에서 작동되는것이 목적이다.

  • 자바 코드 실행 중 JVM이 사용되는 방법

    compiler frontend = javac <- 소스 코드 분석 (Analysis)
    compiler backend = JVM <- 어셈블리어로 바꾸는 곳 (Synthesis)

    C의 경우 컴파일러가 해준다. 이 때 얻는 장점은 런타임 중 관여 할 수있다는 것이다.

2. JVM란?

  • JVM 정의

    JvmJava virtual Machine 의 약자로 자바 바이트코드를 실행할 수 있는 가상 환경
  • JVM 구조

    맨 위의 그림에서 보았다 싶이
    클래스 로더(Class Loader)가 컴파일된 자바 바이트코드를 런타임 데이터 영역Runtime Data Areas)에 로드하고, 실행 엔진Execution Engine)이 자바 바이트코드를 실행한다.

3. 클래스 로더

정의: 자바의 동적 로드를 담당하는 부분이 JVM의 클래스 로더이다.

클래스 로딩을 하는 ClassLoader가 하는 일은 위와 같이 크게 세 가지로 나뉘어진다.

3-1. Loading

Class Loader가 하는 클래스 로딩과 관련된 일들은 한다.
Loading의 특징으로는

  • 계층 구조: 클래스 로더끼리 부모-자식 관계를 이루어 계층 구조로 생성된다.
    (최상위 클래스 로더는 부트스트랩 클래스)

  • 위임 모델(Delegation Hierarchy Model): 계층 구조를 바탕으로 클래스 로더끼리 로드를 위임하는 구조로 아래와 같이
    Bootstrap > Extension > Application(System) > Custom (Bootstrap이 우선순위가 높음)
    Class Loader는 우선순위가 높은 클래스를 로딩한다.

    • Bootstrap Class Loader
      자바에 기본적으로 내장되어 있는 클래스들을 로딩하는 Class Loader이다.
      ( JVM을 기동할 때 생성되며, Object 클래스들을 비롯하여 자바 API들)
      이러한 내장 클래스들은 rt.jar라는 jar파일에 담겨져있다.

    • Extension Class Loader
      $JAVA_HOME/lib/ext 디렉토리에 존재하는 클래스와
      java.ext.dirs 시스템 변수에 저장된 클래스들을 로딩하는 Class Loader이다.
      (기본 자바 API를 제외한 확장 클래스들을 로드한다. 다양한 보안 확장 기능)

    • Application Class Loader
      애플리케이션 수준에 존재하는 클래스들을 로딩하는 Class Loader이다.
      개발자가 직접 작성한 클래스들이 여기에 해당된다.
      (사용자가 지정한 $CLASSPATH 내의 클래스들)
      System Class Loader라고도 한다.

    • User-Defined Class Loader
      애플리케이션 사용자가 직접 코드 상에서 생성해서 사용하는 클래스 로더이다.

  • 가시성(Limit Visibility): 하위 클래스 로더는 상위 클래스 로더의 클래스를 찾을 수 있지만, 상위 클래스 로더는 하위 클래스 로더의 클래스를 찾을 수 없다.

  • 언로드 불가(Unload Not Possiable): 클래스 로더는 클래스를 로드할 수는 있지만 언로드할 수는 없다. 언로드 대신, 현재 클래스 로더를 삭제하고 아예 새로운 클래스 로더를 생성하는 방법을 사용할 수 있다.

3-2. Linking

  • 검증(Verifying): 읽어 들인 클래스가 JVM에 명시된 대로 잘 구성되었는지 검사하는 부분

  • 준비(Preparing): 클래스가 필요로하는 메모리를 할당하는 부분

  • 분석(Resolving): 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 메모리 상에서 실제로 존재하는 물리적인 주소로 변경하는 부분

    클래스 파일이 JVM에 올라가게 되면 심볼릭 레펀선스는 실제 메모리 주소가 아닌 이름에 맞는 객체의 주소를 찾아서 연결하는 작업을 수행한다.

3-3. Initialization

  • 정적(static) 필드들을 설정된 값으로 초기화한다.

4. Runtime Data Area

4.1 Method Area

모든 스레드가 공유하는 영역으로, JVM이 시작될 때 생성된다.
Class Loader에서 로딩한 인터페이스, 클래스에 대한 메서드의 바이트 코드, static 변수 등을 관리하며, 그 중 런타임 상수 풀(Runtime Constant Pool)에서는 모든 메소드와 필드의 메모리 참조 를 담고 있는 테이블을 관리하여 메소드 참조시 JVM은 런타임 상수 풀(Runtime Constant Pool)을 통해 참조한다.

4.2 Heap Area

모든 스레드가 공유하는 영역이자, 인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이다.

  • Young Generation

    젊은 객체가 저장되어있는 곳 (여기서 일어나는 gc는 minor gc라고 불린다.)

    • eden

      객체가 생성되자 마자 저장되는 곳.
      Eden 영역이 가득차 minor gc 가 일어났을 때 S1(From) or S2(To) 중 객체가 있는 곳으로 옮겨짐
    • Survivor

      Minor GC 이후 살아남은 객체들이 Eden 영역에서 양쪽 다 비어있다면 S1(From)에 옮겨진다. 그 후 survivor 영역이 가득차면 Minor gc가 일어나 반대 Survivor 영역으로 이동하고 Age가 증가한다.
      이때 특정 Age값을 넘게 되면 Old Generation으로 넘어가게 된다.
      (이 과정을 promotion이라고 한다.)

      Survivor 두 영역중 하나는 반드시 비어있는 상태다. 만약 두 영역에 모두 데이터가 존재하거나, 사용량이 0이라면 정상적인 상황이 아니다.

  • Old Generation

    늙은 객체가 저장되어있는 곳 (여기서 일어나는 gc는 major gc라고 불린다.)

  • metaSpace

    Metaspace는 Java의 Classloader가 현재까지 로드한 Class들의 Metadata가 저장되는 공간이다.
    (Java 8 나오면서 JVM 영역에서 생긴 변화로, Permanent Generation 메모리 영역이 없어지고 Metaspace 영역이 생겼다.)

    Permanent Generation 영역은 제한된 크기를 가지고 있어 OOM이 발생되었지만, MetaSpace로 바뀌면서 제한된 크기가 사라지고, Native 메모리 영역에 위치하게 되어 문제가 해결되었다.
    (Heap 영역은 JVM에 의해 관리된 영역, Native 메모리는 OS에서 관리하는 영역으로 구분)

4.3 Stack Area

Stack Area는 Stack Frame을 저장하는 공간이며 Method Call당 하나씩 생성된다.
(스레드에 의해 이루어지는 모든 메서드 호출, 중간 계산, 로컬 변수의 할당, 호출 파라미터 등은 런타임 스택에 저장된다.)
스레드 당 하나의 Stack Frame을 가진다.
(스레드를 종료하기 직전 JVM은 스레드와 관련된 Stack을 삭제시킨다.)
스레드와 연결된 데이터를 저장하는 스택은 특정 스레드에만 독점적으로 사용할 수 있으며 다른 스레드에 액세스할 수 없다.(thread-safe)

설명: https://www.tutorialspoint.com/java-virtual-machine-jvm-stack-area

4.4 PC Registers

PC Registers는 Thread가 생성될 때 마다 생기는 공간으로 Thread가 어떠한 명령을 실행하게 될지 기록을 한다.

4.5 Native Method Stack

자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 코드를 실행할 때, Native Method Stack이 할당된다.
(일반적인 메소드를 실행하는 경우 JVM 스택에 쌓이다가 해당 메소드 내부에 네이티브 방식을 사용하는 메소드(예를 들면 C언어로 작성된 메소드)가 있다면 해당 메소드는 네이티브 스택에 쌓인다.)
이 때 JNI (Java Native Interface) 규격에 맞게 적절하게 변경해야 한다.

5. Execution Engine

Execution Engine은 바이트 코드를 실행하는 주체이다.
Runtime Data Area에 존재하는 Method Area의 바이트 코드를 가져와서 실행하게 된다.
이 때, Load 된 바이트코드를 실행하는 Runtime Module이 Execution Engine(실행 엔진) 이다.
Execution Engine이 바이트 코드를 해석하는 방법은 두 가지가 있다.

5.1 Interpreter

Interpreter 방식은 바이트 코드를 한 줄 한 줄 해석하며 실행하는 방식으로 느리다는 단점이 있다.

5.2 JIT Compiler

속도를 개선하기 위해 바이트코드를 JIT 컴파일러를 이용해 프로그램을 실제 실행하는 시점(바이트코드를 실행하는 시점)에 각 OS에 맞는 Native Code로 변환하였다.
하지만, 바이트코드를 Native Code로 변환하는 데에도 비용이 소요되므로, Interpreter와 함께 사용한다.
(보통 일정 수준까지 Interpreter 사용 후 넘어가면 사용한다.)

Reference

[NAVER D2 - JVM Internal]
https://d2.naver.com/helloworld/1230
[JVM, 그래서 넌 뭐야]
https://velog.io/@dhwlddjgmanf/JVM-%EA%B7%B8%EB%9E%98%EC%84%9C-%EB%84%8C-%EB%AD%90%EC%95%BC
[JVM Structure]
https://dzone.com/articles/jvm-architecture-explained
[Minor GC vs Major GC vs Full GC]
https://plumbr.io/blog/garbage-collection/minor-gc-vs-major-gc-vs-full-gc
[10분 테코톡 - 무민의 JVM]
https://www.youtube.com/watch?v=UzaGOXKVhwU&ab_channel=%EC%9A%B0%EC%95%84%ED%95%9CTech

profile
멋진 개발자가 되고 싶어요 youngjun.site

0개의 댓글