JVM

아빠는 외계연·2023년 2월 2일
0

Study

목록 보기
5/11
post-thumbnail

Java Virtual Machine

  • 자바를 실행하기 위한 가상 컴퓨터
  • OS에 종속적이지 않고 CPU가 JAVA를 인식, 실행할 수 있게 하는 가상 컴퓨터
  • 클래스 파일을 기반으로 명령어를 해석하는 추상적 실행머신

  • 컴파일

    • 기계가 인식할 수 있는 언어로 변환해주는 과정
    • 자바는 JVM을 거친 뒤에 OS에 도달하기 때문에 JVM이 인식할 수 있는 *.class로 변환
      • Java Compiler가 .java → .class로 변환
      • 기계어가 아니기 때문에 OS에서 바로 실행X → JVM이 해당 bytecode를 인식할 수 있도록 해석.
  • 자바 바이트 코드

    • JVM이 이해할 수 있는 언어로 변환된 자바 소스코드
    • 실시간 번역기 or JIT 컴파일러에 의해 바이너리(이진) 코드로 변환
      • 바이너리 코드
        • 컴퓨터가 인식가능한 0과 1로 구성된 이진코드
        • CPU가 이해하는 언어
      • JIT(Just-in-time compliation) 컴파일러
        • 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일러

        • 인터프리터 방식을 사용하다가 적절한 시점에 컴파일

        • 인터프리터 방식의 단점을 보완

          • 프로그램 실행 시 인터프리터를 이용하여 코드를 한줄 씩 읽어나가며 즉시 실행하는 방식
          • 프로그래머가 수정한 사항이 바로 반영됨 → 빠르게 오류 파악 가능
          • 차이 > 컴파일 방식은 전체를 번역 후 실행
        • 네이티브 코드는 캐시에 보관 → 속도가 빠르다.

        • 적절한 시점에 바이트 코드 전체를 컴파일하여 기계어로 변경

        • 컴파일은 인터프리터보다 오래 걸리기 때문에 한 번만 실행되는 코드라면 인터프리팅하는 것이 유리
          - 따라서 JIT컴파일러를 사용하는 JVM은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크 후 일정 정도를 넘을 때만 컴파일을 수행
          - JVM은 인터프리터 모드로 실행하는 동안 애플리케이션을 모니터링하면서 가장 자주 실행되는 코드 파트를 발견하여 JIT 컴파일을 수행(비용이 비싸기 때문)

          ⇒ Hotspot JVM에서 실행

        • 프로파일링을 통해 핫스팟을 찾아낸 뒤 해당 부분에 대한 네이티브 코드를 생성

  • JVM 구성요소

  • 클래스 로더
    • 컴파일을 마친 클래스 파일을 읽어들임
    • 로딩된 클래스들을 Runtime Class Area에 배치한다.
    • JVM 내로 클래스 파일을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈
    • 런 타임 시 동적으로 클래스를 로드하고 jar파일 내 저장된 클래스들을 JVM 위에 탑재한다.
      • 클래스를 처음으로 참조할 때 해당 클래스를 로드 및 링크하는 역할
    • 로드 / 링크 / 초기화 진행
  • 동적로딩
    • 로드타임 동적로딩
      • 동적으로 클래스를 로딩하는 것
    • 런타임 동적로딩
      • 클래스를 로딩하는 순간이 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것
  • 실행엔진
    • 클래스를 실행시키는 역할
      • 클래스 로더가 JVM내부의 런타임 데이터 영역에 바이트 코드를 배치 → 실행 엔진에 의해 실행
    • 바이트 코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경
    • 인터프리터
      - 바이트 코드 명령어를 하나씩 읽어서 해석.
      - 전체적인 실행속도는 느리다
      - 기본적
  • 가비지 콜렉터(GC)
    • 더이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제
      - Heap 영역에 생성된 객체 중

Runtime Data Area

  • 프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간

  • PC Register

    • 현재 실행되는 명령어의 주소를 저장
    • 멀티 쓰레드 환경에서 다른 쓰레드에게 점유를 넘겨줄때 어느 부분을 실행해야 하는지 알려준다.
    • 쓰레드가 시작될 때 생성. 스레드마다 하나씩 존재
    • 쓰레드가 어떤 부분을 어떤 명령으로 실행해야 할지에 대한 기록을 하는 부분. 현재 수행중인 JVM 명령의 주소를 갖는다.
  • JVM 스택 영역

    • 메소드를 실행하기 위한 정보들이 저장되는 공간

    • 프로그램 실행 과정에서 임시로 할당되었다가 메소드 밖에서 바로 소멸되는 특성의 데이터를 저장

      • 각종 형태의 변수, 임시 데이터, 스레드나 메소드의 정보 저장
    • 메소드 호출 시마다 각각의 스택 프레임(Frame그 메서드만을 위한 공간)이 생성.

      • 메소드가 끝나면 같이 사라짐
    • 메소드 안에서 사용되는 값들을 저장

      • 매개 변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장
    • 기본형 타입변수 값들은 저장, 객체들은 참조값만 저장(heap 영역에 존재하는 객체들의 참조)

    • 스레드 별로 할당됨

    • 지역변수 배열

      • 지역변수들을 배열에 담고 인덱스로 빠른 접근이 가능
      • 0번 인덱스에는 자기 자신에 대한 참조를 가짐
    • operand Stack

      • 피 연산자들과 연산값들을 저장하기 위함
  • Native Method Stack

    • 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역
    • 자바가 아닌 다른 언어로 작성된 코드를 위한 공간
    • 커널이 스택을 잡아 독자적으로 프로그램을 실행시키는 영역
  • static area(= Method Area, Class Area) → permanent Area

    • 클래스 정보, 멤버 변수, 변수정보, 메서드 정보 등이 저장됨
    • 해당 영역에 대한 GC는 JVM 벤더의 선택사항
    • 클래스 정보를 처음 메모리 공간에 올릴 때 초기화 되는 대상을 저장하기 위한 메모리 공간
  • Runtime Constant Pool

    • 메서드, 필드의 실제 주소를 보관
    • 클래스, 인터페이스마다 존재
    • 각 클래스, 인터페이스의 전역변수/함수, 인스턴스 변수/함수에 대한 심볼릭 링크가 존재
      • 전역 변수/함수는 컴파일 시점에 할당 → 고정된 값으로 존재
      • 인스턴스 변수/함수는 심볼릭링크로 존재하여 실행 시점에 고정된 주소로 변환
    • 클래스가 삭제되면 사라진다.
    • JVM은 런타임 상수풀을 통해 해당 메서드나 필드의 실제 메모리 상 주소를 찾아서 참조
    • 스태틱 영역에 존재하는 별도의 관리영역
    • 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행
  • Heap 영역

    • 런타임 시 생성되는 모든 객체가 저장됨
    • 문자열 상수풀 존재 → gc의 대상이 됨
    • gc가 주로 여기서 동작
    • 객체(인스턴스)를 저장하는 가상메모리 공간
    • new 연산자로 생성되는 객체와 배열을 저장
    • Permanent Generation → 자바 8부터는 heap영역이 아니게 됨
      • 생성된 객체들의 정보의 주소값이 저장된 공간
      • Reflection을 사용하여 동적으로 클래스가 로딩되는 경우에 사용
        • Reflection
          • 객체를 통해 클래스의 정보를 분석해 내는 프로그래밍 기법
          • 컴파일 된 바이트 코드를 통해 역으로 클래스의 정보를 알아내어 사용 가능
    • New/Young 영역
      • 추후 GC에 의해 사라진다.
        • 생명주기가 짧은 젊은 객체를 GC 대상으로 하는 영역
          • Minor GC
    • Eden : 객체들이 최초로 생성되는 공간
      • 해당 영역에 객체가 가득찰 시 첫번째 GC가 발생
        • GC는 Eden 공간에서 개체를 활성상태로 Mark
          • Survivor 0,1 : Eden에서 참조되는 객체들이 저장되는 공간
    • Old 영역
      • 생명주기가 긴 오래된 객체를 GC 대상으로 하는 영역
        • Major GC
          • Minor에 비해 속도가 느리다.
      • New/Young Area에서 일정기간 참조되고 있는, 살아남은 객체들이 저장되는 공간
        • Eden에서 GC로부터 살아남음 → Survivor 1로 이동, Survivor 1에서 GC로부터 살아남음 → Survivor 2로 이동 → 여기서 살아남음 → Old로 이동
    • Constant String Pool
      • String 의 값이 해당 위치에 있다면 반환, 없으면 해당 값을 할당
            
  • Method Area + Heap은 모든 쓰레드가 공유 → 멀티쓰레드 환경에서 동기화에 주의해야 함

    • 모든 쓰레드 종료 시 사라짐

JAVA 프로그램 실행과정

  1. 프로그램 실행 시 JVM은 OS로부터 해당 프로그램이 필요로 하는 메모리를 할당받는다.
  2. 자바 컴파일러(javac)가 자바 소스코드 → 자바 클래스 파일(바이트 코드)로 변환
  3. 클래스 로더를 통해 클래스 파일을 JVM으로 로딩한다.
    1. 어떤 메소드를 만났는 데 해당 메소드를 가진 클래스 바이트 코드가 로딩된 적이 없다면 JVM은 JRE 라이브러리 폴더에서 클래스를 찾는다.
    2. 없으면 CLASSPATH 환경변수에 지정된 폴더에서 클래스를 찾는다.
    3. 찾았으면 바이트 코드를 검증한다.
    4. 올바른 바이트 코드라면 메소드 영역으로 파일을 로딩한다.
    5. 클래스 변수를 만들라는 명령어가 있으면 메소드 영역에 그 변수를 준비한다.
    6. 클래스 블록이 있으면 순서대로 그 블록을 실행한다.
    7. 클래스의 바이트코드가 로딩되면 JVM이 종료될 때까지 유지된다.
  4. Method Area에 클래스 정보를 올린다.
  5. 로딩된 클래스 파일들은 Execution Engine을 통해 해석
  6. 해석된 바이트 코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어진다.
    1. 실행과정 속에서 GC와 같은 작업 수행
profile
Backend Developer

0개의 댓글