[JAVA] JDK, JRE, JVM

D A S H B O A R D
D E V E L O P
S E C U R I T Y
 JDK vs JRE
 JVM (Java Virtual Machine)
자바 프로그램 실행 과정
 JVM 상세 구조
주요내용
Reference

 JDK vs JRE

JDK (Java Development Kit)

JDK는 자바 애플리케이션을 개발하는 데 필요한 Development Tools + JRE이다.
Development Tools에는 개발 시 필요한 javac(컴파일러), 디버거, javadoc 등의 개발 도구들을 포함
JDK를 설치하면, JRE와 JVM이 모두 설치되는 구조
Write Once Run Anywhere

JRE (Java Runtime Environment)

JRE는 자바 애플리케이션을 실행하는 데 필요한 환경을 제공한다.
즉, 자바 애플리케이션 실행을 위해서는 JRE만 있으면 된다.
JRE는 자바 가상 머신(JVM)과 자바 클래스 라이브러리 등을 포함합니다.
실행환경이기 때문에 write의 권한 없이 read및 execute 권한만 존재
JDK vs JRE
JDK는 개발에 필요한 모든 도구를 포함하고 있지만, JRE는 자바 애플리케이션을 실행하는 데 필요한 도구만 포함하고 있다는 것이다.
JDK에 포함된 주요 개발 도구
JAVA JDK 폴더 내 bin 폴더에 여러 Development Tools들이 존재
javac : 자바 컴파일러로 자바 소스를 바이트 코드로 변환
jdb : 자바 응용프로그램의 실행 중 오류를 찾는 데 사용하는 디버거
java : 자바 프로그램 실행기 → 자바 가상 기계를 작동시켜 자바 프로그램 실행
javadoc : 자바 소스로부터 HTML 형식의 API 도큐먼트 생성
jar : 자바 클래스 파일을 압축한 자바 아카이브 파일(.jar) 생성, 관리
jmod : 자바의 모듈 파일(.jmd)을 만들거나 모듈 파일의 내용 출력
jlink : 응용프로그램에 맞춘 맞춤형 JRE 생성
javap : 클래스 파일의 바이트 코드를 소스와 함께 보여주는 디어셈블러
바이트 코드?? 바이너리 코드??
바이너리 코드는 기계어로 0과 1 즉, 이진법으로 작성된 코드다. 이는 CPU가 읽을 수 있는 코드라 볼 수 있다.
바이트 코드는 CPU가 아닌 JVM이 읽을 수 있는 코드.class 로 변환된다. → 기계어로 변환되기 전 어셈블리와 비슷하다 생각하면 펀하다.

 JVM (Java Virtual Machine)

JVM은 자바 애플리케이션을 실행하기 위한 가상 머신이다.
한정된 메모리를 효율적으로 사용하여 최고의 성능을 내기 위해서 Virtual Machine을 사용
JVM은 자바 소스코드로부터 (컴파일 과정을 거쳐)만들어지는 자바 바이너리 파일(.class)을 실행한다.
JVM을 사용하면 하나의 바이트 코드(.class)로 모든 플랫폼에서 동작 가능 - JAVA는 플랫폼 종속적이지 않다!
Java는 플랫폼에 종속적이지 않지만 JVM은 플랫폼에 종속적이다.
Java는 컴파일된 바이트코드로 어떤 JVM에서도 동작시킬 수 있기 때문에 플랫폼에 의존적이지 않다.
하지만 반대로 자바 가상 머신(JVM)은 플랫폼에 의존적입니다. 즉 리눅스의 JVM과 윈도우의 JVM은 서로 다르다.
즉, JAVA는 플랫폼 종속적이지 않기 때문에, 컴파일된 바이너리 코드는 어떠한 JVM에서도 동작한다.
JVM이 플랫폼 종속적인게 아닌 JRE가 플랫폼 종속적이다. 라는 논쟁이 있어서 이에 대해서는 댓글로 토론해보고 싶네요….

자바 프로그램 실행 과정

1.
자바로 개발된 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당합니다.
2.
자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트코드(.class)로 컴파일합니다.
3.
클래스 로더를 통해 JVM Runtime Data Area로 로딩
4.
로딩된 .class 바이트 코드를 실행할 컴퓨터에 깔린 JVM에 가져다주면 그 컴퓨터가 이 프로그램을 실행할 때 JVM이 그때그때 기계어로 해석
자바 인터프리터와 JIT 컴파일러 두 가지 모두 사용하는 이유는 아래 실행엔진 설명 참고

 JVM 상세 구조

1. 메모리 (Runtime Data Areas)

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역

모든 스레드가 공유해서 사용 (GC의 대상)

메서드 영역(Method Area)
클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 각종 필드 정보들
메서드 정보, 데이터 Type 정보, Constant Pool(리터럴 상수 값을 저장), static변수, final class 등이 생성되는 영역
힙 영역 (Heap Area)
new 키워드로 생성된 객체와 배열이 생성되는 영역
주기적으로 GC가 제거하는 영역

스레드(Thread) 마다 하나씩 생성

스택 영역 (Stack Area)
지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역
PC 레지스터 (PC Register)
Thread가 생성될 때마다 생성되는 영역으로 프로그램 카운터, 즉 현재 스레드가 실행되는 부분의 주소와 명령을 저장
네이티브 메서드 스택 (Native Method Stack)
자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역으로 일반적인 C 스택을 사용

2. 클래스 로더(Class Loader)

자바는 동적으로 클래스를 읽어오기 때문에 프로그램이 실행중인 런타임에서 JVM과 연결된다.
한 번에 메모리에 모든 클래스를 로드하는 것이 아닌, 필요한 순간에 해당 클래스(.class) 파일을 찾아 메모리에 로딩해주는 역할
JVM의 실행 엔진이 사용할 수 있도록 Runtime Data Area의 메소드 영역에 적재
클래스 로더에 대한 자세한 설명은 아래 글 참고

3. 실행 엔진 (Execution Engine)

실행 엔진은 클래스를 실행시키는 역할
클래스 로더가 JVM 내의 런타임 데이터 영역에 바이트 코드를 배치시키고 이것은 실행 엔진에 의해 실행
자바 바이트 코드로 이루어진 .class 파일은 기계가 바로 수행할 수 있는 언어보다는 비교적 인간이 보기 편한 형태로 기술된 것
따라서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경해준다.
즉, JIT 컴파일러와 JAVA 인터프리터를 포함하고 있다.
인터프리터와 JIT 컴파일러를 모두 사용하는 이유
인터프리터
바이트 코드를 한줄 씩 해석해 실행하는 방식
초기 방법
속도가 느림
JIT(Just In Time) 컴파일러
프로그램을 실제 실행하는 시점(바이트코드를 실행하는 시점)에 각 OS에 맞는 Native Code로 변환
느린 속도 보완을 위해 등장
바이트코드를 Native Code로 변환하는 데에도 비용이 소요되므로, JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다가 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행
컴파일 임계치(Compile Threshold)
JIT 컴파일러가 메소드가 자주 사용되는 지 체크하는 방식으로 컴파일 임계치를 사용합니다. JIT 컴파일러가 내부적으로 메서드가 호출될 때마다 호출 횟수를 카운팅하고 그 횟수가 특정 수치를 초과할 때 캐싱해서 이후에는 JIT 컴파일이 트리거된다.
JIT 컴파일러는 같은 코드를 매번 해석하지 않고, 실행할 때 컴파일을 하면서 해당 코드를 캐싱해버립니다. 이후에는 바뀐 부분만 컴파일하고, 나머지는 캐싱된 코드를 사용
컴파일 임계치는 method entry counter(JVM 내에 있는 메소드가 호출된 횟수) + back-edge loop counter(메소드가 루프를 빠져나오기까지 회전한 횟수)이다.

4. GC(Garbage Collector)

더이상 참조되지 않는 객체를 모아서 정리
개발자들이 메모리 관리를 비교적 신경쓰지 않아도 되기 때문에, 편리
가비지 컬렉션 중에서 마이너 GC의 경우에는 보통 0.5 이내에 끝나기 때문에 큰 문제가 되지 않지만, 그러나 FULL GC의 경우에는 자바 애플리케이션이 멈춰 버리기 때문에, 문제가 될 수 있다.
멈추는 동안 사용자의 요청이 큐에 들어있다가, 순간적으로 요청이 한꺼번에 들어오기 때문에 과부하에 의한 여러 장애를 만들 수 있다.
따라서 원활한 서비스를 위해서는 GC가 어떻게 일어나게 하느냐가 시스템의 안정성과 성능에 큰 변수로 작용할 수 있다.
GC 에 대한 자세한 설명은 아래 글 참고