[Java] Java와 JVM

2022. 11. 30. 21:51Programming/Java

[Java] Java와 JVM 

 

Java를 사용을 하면서 Java가 어떻게 코드를 인식하고 실행하는지에 대해 학습하는 시간을 가지게 되었다. 해당 글은 그 내용들을 정리하면서 작성하게 되었다.

 

프로그래밍 언어

 

프로그래밍 언어 발전과정

 

프로그래밍 언어 - 컴퓨터가 실행할 프로그램을 작성하는 언어이다.

 

이때 CPU는 기계어 - 이진수(binary code)인 0과 1만 이해가 가능하다. 그렇지만 사람이 기계어로 직접 프로그램을 작성하는 것은 어려운 일이기에 기계어를 ADD / SUB / MOVE 등의 상징적인 기호로 1대 1 대응을 한 어셈블리어가 등장하게 된다. 다만 이 어셈블리어 또한 사람이 직접 다루기는 어렵기에 C / C++ / Java 등의 이해하고 표현하기 쉬운 언어가 등장하게 되는데 이러한 언어를 고급 언어라고 한다.

 

 

이때 자바는 고급언어에 속해있으면서 객체끼리의 상호작용을 표현하며 프로그래밍을 진행하는 언어이기에 객체지향 언어라고 한다. 또한 절차 지향 언어의 경우 각 문제를 순차적으로 진행하는 것을 표현한 언어인데 이 경우 c언어가 존재한다.

 

프로그램 작성

 

실행 과정

  1. 개발자는 먼저 고급언어를 이용하여 소스 프로그램(a.java)을 작성한다.
  2. 작성이 된 소스 프로그램은 Java 컴파일러를 통해 기계어로 변환이 된다.
  3. 변환이 된 코드는 기계어로 이루어져 있으며 class파일로 변환이 된다. 
    1. 이때 기계어 코드로 변환이 되는 과정을 Compile이라 한다.
    2. 컴파일을 전담하는 소프트웨어를 컴파일러라고 한다. 
    3. 자바의 경우 JIT 컴파일러가 존재한다.
  4. 기계어로 변환이 된 class파일을 이제 JVM에서 실행하게 된다.
    1. WORA - Write Once Run Anywhere
    2. Java의 경우 JVM위에서 실행이 되기 때문에 OS에 따라 코드를 다르게 작성할 필요가 없다. 이러한 특성을 플랫폼 독립적이라고 한다. 플랫폼에 JVM이 깔려있으면 Java는 실행을 시킬 수 있다. 

 

바이트 / 바이너리 코드

더보기

바이트 코드  vs  바이너리 코드

처음에는 둘이 다르게 부르는 같은 의미를 지닌 단어인 줄 알았다. 하지만 실제로는 찾아보니 차이가 존재했다

 

바이너리 코드

 

- 컴퓨터가 인식할 수 있는 0과 1로 이루어진 이진 코드를 의미

 

기계어

 

- 0과 1로 이루어진 바이너리 코드

- CPU가 직접 해독하고 실행할 수 있는 비트 단위로 쓰인 컴퓨터 언어

- CPU별로 명령어가 차이가 있을 수도 있다. 

 

 

바이트 코드

 

-가상 머신에서만 실행이 되는 기계어이다. CPU에 제한되지 않기에 가상 머신만 존재하면 프로그램을 실행시킬 수 있게 되는 것이다. 컴파일러가  소스 프로그램을 컴파일하여 바이트 코드로 이루어진 class 파일을 생성하면 JVM은 이 바이트 코드로 이루어진 클래스 파일을 읽어 프로그램을 실행시킨다.

 

 

컴파일러 VS 인터프리터

 

컴파일러

  • 고급 언어로 작성이 된 소스코드들을 CPU가 이해할 수 있는 어셈블리어 같은 기계 언어로 변환하는 것을 의미
  • 컴파일러의 경우 소스코드를 읽어서 변환을 하는 것

 

인터프리터

  • 프로그래밍 언어의 소스 코드를 바로 실행하는 프로그램 또는 환경을 명시
  • 소스 코드를 직접 실행
  • 소스 코드를 효율적인 다른 중간 코드로 변환, 변환된 것을 실행
  • 인터프리터 시스템의 일부인 컴파일러가 만든, 미리 컴파일된 저장 코드의 실행을 호출
  • 고급 언어로 작성이 된 소스 코드들을 한 번에 한 줄씩 읽어서 실행하는 프로그램

 

컴파일이 된 프로그램들은 일반적으로 인터프리터로 한 줄씩 읽어 수행하는 경우보다 빠르게 실행이 된다. 파일을 이미 한번 어셈블리어 같은 저급 언어로 바꿨기 때문에 인터프리터로 한 줄씩 읽는 과정을 생략하기 때문이다. 그러나 인터프리터의 경우 기계어로 만들어지는 해당 과정이 필요 없다는 장점이 존재한다. 그렇기에 고급언어로 작성이 된 프로그램을 그 자리에서 바로 실행이 가능하다.

 

현재에 와서는 인터프리터가 JIT 컴파일 등의 기술로 실시간 컴파일을 하기에 컴파일러와 인터프리터 사이의 경계선이 흐려지고 그에 맞춰 구분도 사라져 가는 추세라고 한다.

 

JVM

 

JVM - Java Virtual Merchine

 

처음 그림에서 개발자가  Java로 작성한 소스코드는 최종적으로 JVM에 도달된 후 실행이 된다. 그렇다면 JVM이 어떻게 구성이 되었기에 해당 프로그램을 실행시키는 것일까?

 

JVM 내부

JVM은 아래 리스트와 같이 나눠진다

  • Class Loader Subsystem
  • Runtime Data Area
  • Execution Engine
  • Native Method Libraries

 

Class Loader Subsystem

 

내부 구조


Loading

BootStrap ClassLoader, Extension ClassLoader, Application ClassLoader가 존재한다.

클래스는 이 요소들에 의해 로딩이 된다.

  • BootStrap ClassLoader - 부트 스트랩 클래스 경로에서 클래스를 로드하는 역할이며 rt.jar 외에는 아무것도 존재하지 않는다. 다만 3개의 로더 중 가장 높은 우선순위를 가지고 있다.
  • Extension ClassLoader -  ext 폴더 (jre / lib) 안에 있는 클래스를 로드하는 역할
  • Application ClassLoader - application의 클래스에서 언급된 경로와 환경 변수 등을 로드함.

Linking

단계에 따라서 진행이 된다.

  1. Verification : 바이트 코드 검증 도구를 통해 생성이 된 바이트 코드가 적절한지 여부를 확인한다. 만약 확인이 실패하는 경우 오류를 발생시킨다.
  2. Preparation : 모든 정적(static) 변수에 메모리가 할당되고 기본값이 할당이 된다.
  3. Resolve : 추상적으로 정해진 reference들을 구체화된 reference로 동적으로 변경하는 과정
    1. 오버 라이딩을 통한 동적 바인딩, 다이내믹 디스패치 시 추상 클래스, 인터페이스의 메서드 대신 실제 구체화된 메서드가 인식이 되는 시점

Initialization

모든 Static 변수는 기존에 선언된 값으로 할당이 되고 Static으로 선언이 된 메서드들이 실행이 된다.

 

 

Runtime Data Area

 

Runtime Data Area

 

 

Method Area

  • 모든 스레드가 공유하는 영역
  • 클래스 / static 영역
  • 클래스 로더에서. class 파일을 읽고 데이터를 Method Area 영역에 저장을 하는데 이때 method area가 바로 여기다
  • 클래스 / 인터페이스 / Enum / 메서드 및 변수가 해당 영역에 저장이 된다
  • 이때 해당 영역에 접근한 class만이 heap에 생성이 가능하다.

Heap

  • 모든 스레드가 공유하는 영역
  • 객체들이 생성이 되고 저장이 되는 공간
  • 가베지 컬렉션의 대상이 되는 영역이다. 

Stack

  • 스레드에서 관리하는 영역이다 ( 스레드 별로 하나가 존재)
  • 스레드에서 메서드가 호출이 될 때 해당 메서드의 수행 정보를 저장하는 곳이다
  • 호출이 종료된 경우 해당 Stack에서 제거가 된다. 

 

 

Execution Engine

 

실행 엔진

 

Execution Engine

JIT Compiler

  • JIT - Just In Time 컴파일
  • 실행 전이 아닌 프로그램 실행 중 (런타임에) 컴파일을 포함하는 컴퓨터 코드를 실행하는 방법
  • 소스 코드 변환으로 구성될 수 있지만 기계어, 바이트 코드로 변환되어 직접 실행함

GC 

  • 사용하지 않게 된 객체 메모리를 가비지(garbage)라고 한다
  • 이러한 가비지들을 수집하여 가용 메모리를 만들어준다.
  • System.gc(); 를 호출하면 가비지 컬렉션 강제 요청이다.

 


JNI

Java Native Interface - JNI

  • JVM에서 실행되는 java코드가 다른 언어로 작성된 라이브러리 및 프로그램에서 호출할 수 있도록 하는 외부 함수 인터페이스 프로그래밍 프레임워크 
  • Java를 사용해서 애플리케이션을 완전히 작성할 수 없는 상황에서 다른 언어로 해당 메서드를 작성할 수 있게 한다.
  • 자바에서 기본으로 제공되는 메서드에 native 키워드가 붙은 경우이다.

Native Method Libraries

  • C , C++로  작성이 된 라이브러리

 

 

출처

바이트코드 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

기계어 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

바이너리 코드 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

명품 JAVA Programming - YES24

컴파일러 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

인터프리터 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)

JVM 아키텍처 설명 - DZone

 

'Programming > Java' 카테고리의 다른 글

[Java] 정규표현식  (1) 2022.12.27
[Java] Thread / Thread 클래스, Runnable 인터페이스 이용  (0) 2022.12.03
[Java] 객체지향설계 - SOLID  (0) 2022.11.21
[Java] Stream이란?  (0) 2022.11.15
[Java] 객체지향  (0) 2022.11.14