...
자바를 처음 설치하면 C:\Program Files\Java 폴더에 아래와 같이 JDK와 JRE 가 각각 설치되는 것을 볼 수 있다.
그렇다면 이 JDK와 JRE의 역할은 무엇인지 그리고 자바 프로그램(JVM)은 어떤식으로 돌아가는지에 대해 정리해보는 시간을 가져보자.
JDK (Java Development Kit)
JDK는 자바 개발키트(Java Development Kit)의 약자로 개발자들이 자바로 개발하는 데 사용되는 SDK 키트라 생각하면 된다.
그래서 JDK안에는 자바를 개발 시 필요한 라이브러리들과 javac, javadoc 등의 개발 도구들을 포함되어 있고, 개발을 하려면 자바 프로그램을 실행도 시켜줘야 하기 때문에 뒤에서 배울 JRE(Java Runtime Environment)도 함께 포함되어 있다.
💡 SDK란?
Software Development Kit (소프트웨어 개발 키트) 로, 하드웨어 플랫폼, 운영체제 또는 프로그래밍 언어 제작사가 제공하는 툴이다. 키트의 요소는 제작사마다 다르다.
SDK의 대표적인 예로, 안드로이드 스튜디오 등이 있다. 이 SDK를 활용하여 애플리케이션을 개발할 수 있다.
아래 그림에서 볼수 있듯이 JDK는 JVM, JRE를 모두 포함하고, 이외에 자바를 개발 하는데 필요한 development tools 도 포함하고 있는 걸 알 수 있다.
JDK 버전 표기
자바의 버전을 표현할 때에는 보통 JDK 또는 Java SE 버전으로 나타낸다.
초기 버전인 1.0/1.1 버전에서는 JDK 1.0 / JDK 1.2 이런식으로 버전 표기를 사용했지만, JDK 1.2를 발표하면서 J2SE로 변경하게 된다. 그리고 J2SE(Java2 Standard Edition)라는 명칭 또한, 2006년 JDK 1.6부터 Java SE(Java Standard Edition)로 변경된다.
실제로 JDK 다운로드 하는 공식 사이트에 가면 다음과 같이 JAVA 버전이 표기 되어 있는 걸 볼 수 있다.
- Java SE(Java Standard Edition) : 가장 기본이 되는 표준 에디션의 자바 플랫폼으로 자바 언어의 핵심 기능을 제공
- 가장 기본적인 클래스 패키지로 구성
- PC용 어플리케이션, 애플릿개발, 응용프로그램개발, 웹개발, 안드로이드개발
-
PC에 설치해서 사용할 수 있는 모든 프로그램 개발에 관련된 것
- Java EE(Java Enterprise Edition) : 대규모 기업용 에디션. SE확장판(대형 네트워크환경 프로그램 개발시)
- 기업환경을 위한 대규모 솔루션 개발, 모바일폰, 셋탑 박스, 차량용 텔레매틱스 시스템 개발
- Java ME(Java Micro Edition) : 피쳐폰, PDA폰, 셉톱박스, 프린터와 같은 작은 임베디드 기기들 같은 작은 기기를 다루는데 이용하는 에디션
- JAVA SE를 줄여 라이트하게 만든 것이 므로 SE개발을 할 줄 알면 ME기반의 개발도 가능
- 각각의 OS(ex. Android OS, IOS, Black Berry 등)를 가지고 있는 스마트 폰이 대중화된 지금은 잘 쓰이지 않는다
- JavaFX : 가볍고 예쁜 그래픽 사용자 인터페이스(GUI)를 제공하는 에디션
- 고성능의 하드웨어 그래픽 가속과 미디어 엔진 API를 제공해주어서 프로그램의 성능에 신경을 써야 하는 분야에서 사용
정리하자면, 사람들이 JAVA라고 하고 JAVA 11이라 하는것은 결국 JDK의 버전을 의미한다고 볼 수 있다.
그래서 Java를 설치한다 라는 것은 JDK를 설치한다 라고 할 수 있다.
Java 상세 버전 표기법
- 주 버전 : 자바 언어에 많은 변화가 있을 경우 증가
- 개선 버전 : 주 버전에서 일부 사항이 개선될 때 증가.
- 업데이트 버전 : 1~3개월 주기로 버그가 수정될 때마다 증가.
- LTS : 장기 지원 서비스(Long Term Support)를 받을 수 있는 버전
JDK 종류
자바는 워낙에 유명한 프로그래밍 언어이기 때문에 JDK도 여러가지 종류로 나뉜다. (리눅스 처럼 Ubuntu, CentOS, RedHat 계열이 있는 것과 같다)
이처럼 여러가지 JDK가 있는 큰 이유는 라이센스 때문이다.
Java 소스코드 자체는 오픈소스이다.
그래서 오픈소스인 Java 소스코드를 빌드하여 사용하는 것에는 거의 제약이 없지만 Oracle에서 제공하는 설치버전의 JDK에는 위의 NFTC 라이센스가 적용되어 회사에서는 사용할 수 없게 된다. (따로 돈내고 사용해야 된다)
그래서 무료 라이센스를 제공하는 또다른 JDK 버전을 여러 회사에서 출시했고 지금의 JDK 환경이 갖춰진 것이다.
위와 같이 정말 많은 JDK가 있지만, 주요 JDK 종류로는 다음과 같다.
- Oracle JDK : Oracle에서 제공하는 JDK. 구독을 통해 유료 라이센스를 구매할 수 있다.
- Open JDK : 유명한 무료 JDK. 하지만 OpenJDK를 직접 사용하는것 보다는, OpenJDK 기반으로 빌드된 JDK 사용을 추천한다.
- Azul Zulu : 인지도가 높은 JDK 중 하나이며, Mac 등에서 사용할 수 있는 바이너리를 제공하는 것이 특징이다.
- Amazon Corretto : AWS에서 제공하는 JDK. AWS에서 쉽게 사용 가능하며, AWS 환경이 아니더라도 사용할 수 있다.
- Temurin (AdoptOpenJDK) : Eclipse에서 제공하는 JDK. Eclipse를 사용한다면 Temurin 설치를 추천한다.
[ JDK 선택 방법 TIP ]
1. 라이센스 확인
사용 목적에 따라서 라이센스 확인이 가장 중요하다.
Oracle JDK를 제외하고, 위에 소개된 JDK는 모두 무료로 사용할 수 있다.
2. 업데이트 지원
보안 패치 등을 포함하여 업데이트 지원은 자바 상용 프로그램을 개발하는데 있어 매우 중요하다.
자바 버전 옆에 LTS 라고 써있는 것이 바로 보안 패치를 장기적으로 지원한다는 의미이다.
JDK 디렉토리 구성요소
- bin : 자바 개발, 실행에 필요한 도구와 유틸리티 명령
- include : 네이티브 코드 프로그래밍에 필요하는 C언어 헤더 파일
- lib : 실행 시간에 필요한 라이브러리 클래스들
bin 디렉터리에 들어 있는 개발 프로그램
- javac : 자바 컴파일러로 자바 소스를 바이트 코드로 컴파일
- java : 자바 인터프리터. 컴파일러가 생성한 바이트 코드를 해석하고 실행
- javadoc : 자바 소스로부터 HTML 형식의 API 도큐먼트 생성
- jar : 자바 클래스 파일을 압축한 자바 아카이브 파일(.jar) 생성, 관리하는 압축 프로그램 (zip 같은거라 생각하면 된다)
- jmod : 자바의 모듈 파일(.jmd)을 만들거나 모듈 파일의 내용 출력
- jlink : 응용프로그램에 맞춘 맞춤형 JRE 생성
- jdb : 자바 응용프로그램의 실행 중 오류를 찾는 데 사용하는 디버거
- javap : 역어셈블러. 컴파일된 클래스 파일을 원래의 소스로 변환
JRE (Java Runtime Environment)
JRE는 자바 실행환경(Java Runtime Environment)의 약자로서, JVM과 자바 프로그램을 실행(동작)시킬 때 필요한 라이브러리 API를 함께 묶어서 배포되는 패키지 이다. 이외에도 자바 런타임 환경에서 사용하는 프로퍼티 세팅이나 리소스 파일(jar 파일)을 가지고 있다.
JRE는 기본적으로 JDK에 포함되어 있기 때문에 JDK를 설치하면 함께 설치된다.
기존에는 개별적으로 설치가 가능했지만 JDK11 버전부터는 따로 제공되지 않는다고 한다.
간단히 정리하자면, Java로 프로그램을 직접 개발하려면 JDK가 필요하고, 컴파일 된 Java 프로그램을 실행시키려면 JRE가 필요하다고 보면 된다.
JVM (Java Virtual Machine)
JVM은 자바 가상머신(Java Virtual Machine)의 약자로서, 직역하면 자바를 실행하는 머신이라는 건데, 그냥 자바를 돌리는 프로그램 정도로 이해하면 된다.
자바로 작성된 모든 프로그램은 JVM(자바 가상 머신)에서만 실행될 수 있으므로, 자바 프로그램을 실행하기 위해서는 반드시 자바 가상 머신이 설치되어 있어야 한다.
앞서 말했듯이 JVM은 자바 실행 환경 JRE(Java Runtime Environment)에 포함되어 있다. 그래서 현재 사용하는 컴퓨터의 운영체제에 맞는 자바 실행환경 (JRE)가 설치되어 있다면 자바 가상 머신이 설치되어 있다는 뜻이기도 하다.
JAVA라는 프로그래밍 언어가 인기 있는 핵심 이유중 하나가 바로 이 JVM 개념인데,
JVM을 사용함으로써 얻는 가장 큰 이점은 JVM을 사용하면 자바 프로그램을 모든 플랫폼에서 제약 없이 동작하도록 할 수 있다는 점이다.
이제 부터 이에 대해 자세히 알아보는 시간을 가져보자.
왜 JVM이 필요한가?
Java 는 OS에 종속적이지 않다는 특징을 가지고있다.
OS에 종속받지 않고 실행되기 위해선 OS 위에서 Java 를 실행시킬 무언가가 필요한데 그게 바로 JVM(Java를 실행할 수 있게 하는 가상 컴퓨터)이다.
OS에 종속받지 않는것이 무슨 의미인지 기존 C언어외의 비교를 통해 알아보자.
C언어의 실행 (WOCA)
학부에서 c언어 코드를 작성하고 저장하고 실행하면 exe 파일로 떨어져, 그 exe 파일을 실행하면 c언어 코드가 실행된 결과를 얻는 경험을 한번쯤은 해보았을 것이다.
이렇게 개발자가 소스 코드를 작성하면, 기계에 맞춰진 컴파일러가 각 기계가 이해하는 기계어로 변환해주어 실행 프로그램(exe)를 만들어 주는 것이다.
이렇게 컴파일된 코드를 Binary code(기계가 읽을 수 있는 이진 코드, 기계어)라고 부른다.
이를 WOCA의 특성이라 부르며, "Write Once, Compile Anywhere" '한번만 작성하고 컴파일하면 어디서든 사용 가능하다' 를 의미한다.
그런데 이 기계어는 특정 OS나 CPU 구조에 맞춰진 컴파일러에 의해 다르게 컴파일이 된다는 특징이 있다.
이 말은 다양한 환경의 기기(다른 OS, CPU 구조)를 사용하는 환경에서는 이 기계어를 이해할 수 없다는 말이다.
컴파일러는 같은 형식의 기계어를 만들어내지만, 각 OS 환경에 맞춰진 독자적인 컴파일러이기 때문에 다른 환경에서는 이해하지 못하기 때문이다.
그래서 학부에서 리눅스 과정을 들을때 C언어를 코딩하면서 무언가 다른 문법에 익숙치 않은 경험을 가지고 있을 텐데 이것이 그 이유이기도 하다.
그래서 이를 "이식성이 낮다" 고 표현하기도 한다.
보통 C언어를 OS에 종속된 언어라고도 표현하는데, 윈도우 OS 환경에서 컴파일된 코드가 리눅스 OS환경에서는 읽어질 수 없기에, 개발자는 윈도우용 C 프로그램, 리눅스용 C 프로그램을 또 만들어야 되서 OS 환경에 종속 되었다고 말한다.
JAVA의 실행 (WORA)
이렇게 컴파일러가 운영체제마다 의존적이었던 문제를 해결하고자 JAVA(JVM)가 등장하게 된다.
JAVA 언어로 작성한 소스파일은 직접 운영체제로 가서 실행하는 것이 아닌, JVM을 거쳐서 운영체제와 상호작용을 하게 된다.
이말은 JVM만 있으면 운영체제가 리눅스든, 맥이든 관계없이 운영체제로부터 독립적으로 프로그램을 제약없이 실행할 수 있다는 의미이다.
이것이 가능한 이유는 컴파일된 코드와 하드웨어/OS 사이 중간에서, 해당 하드웨어/OS 환경에 알맞게 JVM이 Byte Code로 변환해주기 때문이다.
이전까지는 다양한 OS 환경에 맞춰진 컴파일러가 이해할 수 있도록 직접 코드 변경이 필요했지만 자바는 그럴 필요가 없어졌다.
위의 그림처럼 서로 다른 운영체제라도 자바 가상 머신만 설치되어 있다면, 같은 자바 프로그램이 아무런 추가 조치 없이 동작할 수 있다. 따라서 개발자는 한 번만 프로그램을 작성하면, 모든 운영체제에서 같이 사용할 수 있는 장점이 있다.
위에서 C언어에서의 컴파일 과정은 소스 코드를 Binary Code(기계어)로 바로 변환하여 하드웨어에 의해 읽어지고, 그렇기 때문에 OS 환경에 따라 코드가 달라져야했던 것과 달리, Java는 아래의 과정을 거치는 것을 통해 코드의 수정이 불필요하게 된다.
- Java Compiler가 JAVA로 작성된 소스 코드 .java 파일을 .class 파일인 Byte Code로 컴파일한다.
(단, 해당 코드는 직접 CPU에서 동작할 수 있는 코드가 아니다. 정확히 말하면 가상머신 JVM이 이해할 수 있는 코드이다) - 이제 이 Byte Code를 기계어로 변환시키기 위해 가상 CPU가 필요한데, 이것이 JVM(Java Virtual Machine)의 역할이다.
- JVM이 Byte Code를 기계어(Binary Code)로 변환한다.
- 이렇게 JVM에 의해 컴파일된 기계어는 바로 CPU에서 실행되어 사용자에게 서비스를 제공해준다.
[ 바이너리 코드 ]
컴퓨터가 인식하고 이해할 수 있는 0과 1로 구성된 코드이지만, 환경에 종속적이며 실행하지 못한다.
'링커'에 의해 메모리 주소값을 반영하고 CPU가 직접 해독하고 실행할 수 있도록 수정되어야 기계어가 되는 것이기 때문에 가장 기계어와 유사한 레벨의 코드지만 따지자면 완전한 기계어는 아니다.
[ 바이트 코드 ]
가상머신(JVM, CLR 등)에서 사용되는 코드 개념으로, 가상머신이 이해할 수 있는 중간 레벨로 컴파일 한 것을 말한다.
따지자면 반쪽짜리 컴파일 결과물 이기도 하다.
이는 어셈블리어와 유사한 형태를 띄고 있으며, 실행되기 위해서는 컴파일러(javac, csc.exe 등) 에 의해 한번 더 변환되어야 한다.
바이너리 코드와 달리 어떠한 환경에 종속적이지 않고 실행될 수 있다.
이처럼 JAVA는 WORA의 특성이라고 불리우며, "Write Once, Read Anywhere"이라는 재컴파일할 필요기 없고 바로 기계가 읽고 실행할 수 있게 한다는 의미로 쓰여진다.
즉, 윈도우 환경에서 컴파일한 Byte Code를 맥, 리눅스 환경에서도 제약없이 동작한다는 것은, JVM이 자바 파일을 한번 더 기계어로 변환해주기 때문에 가능한 것이다.
이로 인해 JAVA언어는 이식성이 높은 특성을 갖게 되었다.
단, 간과하지 말아야 할 점은 자바 프로그램과는 달리 자바 가상 머신(JVM)은 운영체제에 종속적이므로, 각 운영체제에 맞는 자바 가상 머신을 설치해야 한다는 점이다.
어쩌면 사용자 입장에선 C로 작성된 프로그램이든, JAVA로 작성된 프로그램이든 똑같이 운영체제에서 프로그램을 구동하기 위해선 머신을 설치해야 한다는 점에서 별 차이가 없게 느껴질수도 있다.
하지만 개발자 입장에선 윈도우용 C 코드와 리눅스용 C 코드로 작성된 프로그램을 각기 만들어야 하고 또 이들을 각기 유지보수해야 되는 불편함을, JAVA는 한번만 작성되면 각 OS에 맞는 JVM만 잘 설치해주면 구동되기에 효율성과 생산성이 높아진다는 큰 장점을 가지게 된다.
이러한 장점 때문에 자바가 아닌 다른 언어도 클래스 파일만 있다면 JVM을 사용할 수 있게 개발되고 있다.
실제로 Java 외 다른 언어(클로저, 그루비, 코틀린 등)에서도 이 JVM 사용하고 있다.
그러나 장점이 있으면 언제나 단점이 있기 마련이다.
이처럼 자바 프로그램은 일반 프로그램보다 자바 가상 머신이라는 한 단계를 더 거쳐야 하므로, 결국은 상대적으로 실행 속도가 느리다는 단점을 가지고 내포하고 있다.
즉, JAVA는 C언어와 달리 두번의 컴파일로 인한 속도의 문제가 발생하는데, 이를 보완하기 위해 JIT 컴파일러 라는내부 프로그램을 사용해서 필요한 부분만을 기계어로 바꾸어 줌으로써 성능 향상을 가져오도록 했지만 그럼에도 C언어의 실행 속도를 따라잡지는 못했다. (왜 게임이나 임베디드에서 C계열 언어를 사용하는 이유가 바로 이 때문이기도 하다)
[ JIT 컴파일러(Just-In-Time compiler) 란? ]
기존의 자바는 인터프리터 방식으로 명령어를 하나씩 실행하게끔 이루어져 있어 실행 속도가 느렸다.
하지만 하드웨어가 발전하면서 자바 컴파일러도 JIT 컴파일러 방식으로 개선되어 속도적인 측면에서 상당한 개선을 이루었다.
JIT 컴파일러는 같은 코드를 매번 해석하지 않고, 실행할 때 컴파일을 하면서 해당 코드를 캐싱 한다. 이후에는 바뀐 부분만 컴파일하고 나머지는 캐싱된 코드를 사용한다.
동적 번역(dynamic translation)이라고도 불리는 이 기법은 이전의 자바 해석기(Java interpreter) 방식보다 성능이 10배 ~ 20배 정도 더 좋다.
자바 프로그램의 실행 과정
백날 글로만 읽어봤자 한번 실행하는 것보다 못하다라는 말이 있다.
위에서 배운 JVM이 자바 프로그램을 실행 하는 과정을 직접 해보자.
앞서 말했듯이 JVM이라는 특성 때문에 자바로 작성한 파일을 실행하기 위해서는 두 번의 단계를 거쳐야만 한다.
하나는 MyProgram.java 파일을 MyProgram.class 파일로 바꾸어 주는 컴파일 단계이고 두번째는 MyProgram.class 파일을 바이너리 코드(0100101...)로 변환하고 실행하는 단계이다.
위 그림에서 Compiler는 javac.exe에 해당되고 JVM은 java.exe에 해당된다.
위 그림을 순서대로 서술하면 다음과 같다.
- 소스코드(MyPrograme.java)를 작성한다.
- 컴파일러(Compiler)는 자바 소스코드를 이용하여 클래스 파일(MyProgram.class)을 생성한다. 컴파일 된 클래스 파일은 JVM(Java Virtual Machine)이 인식할 수 있는 바이트 코드 파일이다.
- JVM은 클래스 파일의 바이트 코드를 해석하여 바이너리 코드로 변환하고 프로그램을 수행한다.
- MyProgram 수행 결과가 컴퓨터에 반영된다.
왜 자바는 컴파일을 하고나면 exe 파일이 아닌 class 파일이 생성될까?
c 또는 c++ 등으로 작성된 프로그램은 최종 결과물로 exe 파일을 만들어 낸다.
이 exe 파일은 계산기와 같은 프로그램이거나 게임일 수도 있다.
사용자는 그냥 단순히 exe 프로그램을 실행하기만 하면 프로그램을 실행시켜 볼수 있다.
그런데 왜 자바는 실행하기도 어려운 class라는 걸 만들어서 귀찮게 하는걸까?
물론 java도 exe 프로그램으로 만들어 낼 수 있기는 하다.
다만 JVM이 exe에 포함되는 형식으로 가능하기 때문에 exe 파일이 무척이나 커진다는 단점이 있기 때문에 일부러 생성하지는 않는다.
이제 실제로 정말로 저렇게 컴파일이 진행되는지 실습해보자.
다음과 같이 자바 코드 파일을 작성하고 MyProgram.java 라는 자바 확장자 파일로 저장한다.
public class MyProgram {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
이제 이 코드(파일)가 정상적으로 동작하는지 확인하기 위해 프로그램을 실행시켜보자.
Windows를 기준으로, cmd 창을 열고 해당 MyProgram.java 파일이 있는 곳으로 이동한다.
그리고 해당 위치에서 javac 명령어로 컴파일을 진행한다.
> javac MyProgram.java
그러면 현재 위치에 MyProgram.class 파일이 생성된 걸 확인할 수 있다.
MyProgram.class 파일이 만들어졌으면 이제 java 명령어로 MyProgram.class 파일을 실행 시켜 코드의 결과를 얻을수 있게 된다.
그리고 이 java 명령어가 바로 JVM을 실행시키는 것이다.
> java MyProgram # 파일을 실행시킬때 .class 확장자는 뺀다.
Hello World
"Hello World"가 출력되면서 파일이 실행된걸 확인할 수 있다.
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.