과거에 자바의 동작 과정에 대해 간단하게 글을 작성했지만
이 글은 더 자세하게 다시 작성해보았다
Java SE (Java Platform, Standard Edition) : 자바의 기본 버전이다. 자바가 어떤 문법을 가졌고 어떻게 정의되는지를 나타낸다. 해당 자바 플랫폼에는 기본 API와 라이브러리, 도구들이 포함되어있다.
Java EE (Java Platform, Enterprise Edition) : 자바 SE를 기반으로 확장된 버전으로 대규모 분산형 애플리케이션, 웹개발을 위한 버전이다. Servlet, JSP, JPA 등과 같은 기술이 들어가있다
Java ME (Java Platform, Micro Edition) : 기존 버전에 비해 크기가 작아지고 경량화가 된 버전이다. 이를 이용해 모바일, 센서, 가전제품, 자동차 등 자원이 제한된 제품에서 사용하기 좋게 개발된 버전이다.
JDK (Java Development Kit) : 자바 애플리케이션을 개발하기 위해 필요한 도구와 라이브러리를 포함한 패키지이다. JDK에는 자바 컴파일러, 디버깅 도구, 실행 환경, 라이브러리 등이 포함되어 있어 개발자가 자바 애플리케이션을 개발하고 실행할 수 있도록 지원한다. JDK는 자바 SE, EE, ME 등 다양한 버전에 따라 제공되며, 개발자는 해당 버전에 맞는 JDK를 선택하여 사용한다.
JRE (Java Runtime Environment) : 자바 애플리케이션을 실행하기 위한 환경을 제공하는 패키지이다. JRE에는 JVM과 클래스 라이브러리가 포함되어 있으며, 애플리케이션을 실행하는 데 필요한 구성 요소를 제공한다. JDK를 설치하면 기본적으로 JRE가 들어있다
JVM (Java Virtual Machine) : JVM은 자바 애플리케이션을 실행하기 위한 가상 환경을 제공하는 소프트웨어이다.
JVM은 자바 프로그램이 실제 운영체제 상에서 실행되는 과정에서 중간 단계로 동작한다. 자바 컴파일러에 의해 컴파일된 자바 소스 코드는 바이트 코드(Bytecode)로 변환된다. 이 바이트 코드는 JVM에 의해 해석되고 실행된다.
JVM은 클래스로더, 바이트 코드 해석기, 메모리 관리, 가비지 컬렉션, 예외처리 등의 기능을 수행한다
아래는 오라클에서 설명한 자바의 구성 요소이다
JVM은 자바앱을 실행하는 주체로 JVM덕분에 다양한 플랫폼 위에서 동작이 가능하다
JVM의 구조는 다음과 같다
JVM이 자바 애플리케이션을 실행할 때 클래스 파일을 로드하는 역할을 한다.
클래스 로더는 필요한 클래스를 찾고 메모리에 로드하며 링크하는 작업을 수행한다.
클래스 파일을 메모리에 로드하는 과정을 의미한다.
클래스 로더가 클래스 파일을 로드한 후에 수행하는 작업이다.
링킹은 로드된 클래스와 관련된 다른 클래스나 메서드, 필드 등을 연결하는 과정이다.
클래스를 로드한 후에 수행되는 과정이다. 초기화는 클래스와 관련된 정적 변수(static variable)의 값을 설정하고, 정적 초기화 블록(static initialization block)의 코드를 실행하는 작업을 의미한다.
클래스 로더의 초기화 단계에서는 클래스의 정적 변수의 값을 설정하고, 정적 초기화 블록의 코드를 실행하여 클래스의 초기 상태를 설정한다. 초기화는 클래스 로딩 과정의 일부로 자동으로 수행되며, 클래스의 초기화는 클래스의 정적 데이터와 초기화 코드를 처리하는 중요한 역할을 한다.
JVM이 자바 애플리케이션을 실행하는 동안 필요한 데이터를 저장하는 메모리 영역이다
위에서 설명했던 것 처럼 클래스 로더에서 로드된 클래스 정보, 정적 변수, 상수, 메서드 코드등을 저장한다.
메서드 영역은 JVM에 의해 공유되면 애플리케이션이 실행되는동안 계속 유지된다.
동적으로 할당된 객체들이 저장되는 영역이다. 객체, 배열등을 저장하며 실행중에 객체가 생성되거나 소멸될 때 메모리가 동적으로 할당되거나 해제된다. 메모리 해제는 가비지 컬렉션(Garbage Collection)에서 관리한다.
스택 영역은 각 스레드마다 생성되며 각 스레드가 메서드를 호출할 때마다 해당 메서드의 호출 정보와 지역변수를 저장한다. 스택이기때문에 LIPO로 실행된다
JVM이 명령어를 실행하는 동안 프로그램 카운터를 유지하는 역할을 한다.
PC Registers는 스레드마다 독립적으로 관리되며 각 스레드는 다음에 실행할 명령어를 추적할 수 있다.
명령어의 실행이 완료되면 PC Registers는 다음 명령어의 주소로 갱신된다.
자바 코드가 아닌 다른 어언어로 작성된 네이티브 메서드의 호출 정보와 지역 변수를 저장한다.
자바 애플리케이션을 실제로 실행하는 역할을 한다. Execution Engine은 다른 구성 요소와 상호작용하여 자바 바이트코드를 명령어로 변환하고 실행하는 프로세스를 담당한다.
인터프리터는 자바 바이트코드를 한줄씩 읽어와 해당 명령어를 해석하고 실행하는 역할을 한다.
가장 기본적인 실행 방법으로 빠른 실행속도보다는 실행 가능한 독립성과 유연성을 갖는다.
JIT은 인터프리터가 자주 실행되는 코드를 감지하고 해당 코드를 기계어로 컴파일하여 실행 속도를 향상시키는 역할을 한다. JIT은 인터프리터의 느린 속도를 보완하기 위해 동적으로 코드를 최적화하고 반복적으로 실행되는 코드를 컴파일하여 바로 실행 가능한 기계어로 변환한다.
자바 소스코드 (우리가 작성한 코드)를 컴파일한 결과물이다.
이 바이트코드는 JVM에서 실행이 가능한 중간 언어로 활용된다.
javac라는 컴파일러를 사용하여 컴파일을 한다.
자세한건 참고 바람
https://en.wikipedia.org/wiki/Java_bytecode
https://www.softwaretestinghelp.com/java-components-java-platform-jdk
https://dzone.com/articles/jvm-architecture-explained
https://www.oracle.com/java/technologies/platform-glance.html