목차
목표 : 자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기
1. JVM이란 무엇인가
자바의 대표적인 특징 중 하나는 기존의 언어들과 달리 운영체제(OS)에 독립적이라는 것이다.
자바 이전의 C언어 등으로 만들어진 프로그램은 OS에 종속되어 있다. 프로그램이 실행되기 위해서는 OS가 제어하고 있는 HW의 메모리(RAM : 주기억장치)를 제어할 수 있어야 하기 때문이다.
이와 달리 자바가 OS에 독립적일 수 있는 이유는 JVM(Java Virtual Machine : 자바 가상 머신) 덕분이다.
가상 머신이란 실제 컴퓨터가 아닌 소프트웨어로 구현된 컴퓨터라는 뜻이다.
그림의 구조처럼, 일반 애플리케이션과 달리 자바 애플리케이션은 JVM 하고만 상호작용을 하기 때문에 OS와 하드웨어에 독립적이다.
JVM은 애플리케이션으로부터 전달받은 명령을 해당 OS가 이해할 수 있도록 변환하여 전달하는 중간역할을 한다. 단, JVM은 운영체제에 종속적이기 때문에 썬에서는 운영체제 별로 다른 버전의 JVM을 제공하고 있다.
JVM을 실행시키면, OS에게서 메모리 사용권한을 할당받아서 JVM이 자바프로그램을 호출 및 실행하게 되는데,
자바로 작성된 애플리케이션은 모두 JVM에서만 실행되기 때문에, 반드시 JVM이 필요하다.
반면 JVM은 자바 가상머신임에도 자바에 종속적이지 않고, 다른 언어로도 바이트코드를 생성할 수 있다.
2. 자바 설치 맟 컴파일 하는 방법
그럼 이제 직접 자바 프로그램을 짜고 컴파일 해보자.
자바로 작성한 프로그램을 컴파일하고 실행하려면 JDK가 필요하다. 설치과정부터 쭉 정리 해보려고 한다!
컴파일이란 프로그래머가 작성한 소스코드를, 컴퓨터가 실행할 수 있는 바이너리 코드(이진법 0,1)로 변환하는 과정이다.
- JDK는 Java Development Kit(자발 개발 도구)의 약자로, 여러 라이브러리들 및 javac 컴파일러 등이 포함되어 있다.
- JDK 다운로드 링크: java.sun.com/
(※ 예전에 저장해둔 캡쳐라 옛날 버전입니다 !!)
JAVA SE는 Standard Edition의 약자로 표준 Java 버전이다. 참고로 EE는 기업용이다.
설치 후에는 bin 디렉토리를 Path에 추가해주어야 한다.
Path는 OS가 파일의 위치를 파악하는데 사용하는 경로(path)로,
Path 환경변수에 경로를 설정하면 그 경로에 있는 프로그램은 경로명을 지정하지않고도 사용할 수 있다.
(자바를 어떤 환경에서도 실행할 수 있게 하기 위해 필요한 과정이다)
우선 헷갈리지 않도록 JDK 파일의 경로를 환경변수(OS에서 관리하는 변수) JAVA_HOME 으로 추가한다.
🔎 시스템 환경 변수 편집 > 시스템 속성 > 고급 > 환경변수 > 시스템 변수 > 새로 만들기
이제 Path 를 편집하자.
새로 만들기 버튼 클릭 후 Path에 앞서 추가한 환경변수에 bin 경로를 덧붙이고 확인 버튼을 클릭한다.
- %JAVA_HOME%\bin\
잘 설정되었는지 cmd에서 확인해보자.
메모장을 켜고 간단한 자바 코드를 작성한다.
.java 확장자로 파일을 작성하고 cmd에서 javac를 이용해 컴파일 해보자.
컴파일이 잘 됐으면 .class 파일이 생성된다.
3. 자바 파일을 실행하는 방법
HelloJava.class 파일은 bin 폴더에 있는 java.exe 프로그램을 이용해서 실행할 수 있다.
왜 굳이 java.exe 프로그램으로 실행해야 할까?
javac 컴파일러는 JVM에 맞는 가상 기계어 파일을 생성하는데, 그것이 바로 class 파일이다.
JVM은 가상 기계어인 자바 byte code를 진짜 기계어로 번역한다.
java.exe는 그런 JVM을 기동하는 역할을 하고, 그래서 class 파일은 java.exe를 통해서 실행되어야 하는 것이다.
다시 한번 정리해보자. 자바로 작성한 프로그램은 다음의 컴파일 과정을 거친다.
1. 자바 프로그램.java --------javac 컴파일러로 컴파일 -------> .class 확장자의 byte code로 변환
2. java.exe로 JVM을 구동 ----.class 파일을 JVM으로 컴파일 ---> OS에 맞게 컴파일된 코드
3. JVM에 의해 컴파일된 코드는 실행 시에 해석(interpret)되어 하드웨어의 기계어로 변환
4. 바이트코드란 무엇인가
1. 자바 프로그램.java --------javac 컴파일러로 컴파일 -------> .class 확장자의 byte code로 변환
자바 소스를 javac 컴파일러로 컴파일하면 .class 파일이 생성되는데, 이 클래스 파일은 byte code 라고 했다.
byte code는 가상 컴퓨터에서 소스코드를 기계어로 번역하기 위해 설계된 가상 기계어로, 하드웨어가 아닌 소프트웨어에 의해 처리되므로 보통의 기계어보다 더 추상적인게 특징이다.
byte code는 JVM과 같은 가상머신에 의해 실행되어 프로세서에 인식되기 위한 기계어로 컴파일된다.
byte code라고 불리는 이유는, 대부분의 명령 집합이 0개 이상의 매개 변수를 갖는 1바이트 크기의 명령코드이기 때문이다.
그렇다면 왜 굳이 byte code로 컴파일 하는 걸까? 앞서 자바는 OS에 종속적이지 않은게 특징이자 장점이라고 했다.
JVM 자체는 OS마다 다르지만, 모든 JVM은 똑같은 byte code를 쓰기 때문에 클래스 파일을 다른 종류의 OS로 가져가도 그대로 실행할 수 있게 되는 것이다. (이러한 특징을 이식성이 뛰어나다고 표현한다)
5. JIT 컴파일러란 무엇이며 어떻게 동작하는가
2. java.exe로 JVM을 구동 ----.class 파일을 JVM으로 컴파일 ---> OS에 맞게 컴파일된 코드
3. JVM에 의해 컴파일된 코드는 실행 시(Runtime)에 해석(interpret)되어 하드웨어의 기계어로 변환
프로그램을 실행하려면 CPU가 이해할 수 있는 기계어로 컴파일 되어야한다. JVM은 각 byte code를 해석하면서 계산을 수행하는데, 해석 중에 프로세서나 메모리를 추가로 사용하게 되면 속도가 느려지기 때문에 문제가 있었다.
하지만 JIT 컴파일러 등 신기술의 도입으로 속도문제가 상당히 개선되었다.
JIT 컴파일러는 빠른 속도로 byte code를 기계어로 변환하는데, 거의 실시간 속도로 일어난다고 해서 Just-In-Time의 약자이다.
JIT 컴파일러가 속도가 매우 빠른 이유는 다음과 같다.
- JIT 컴파일러는Compile Time / RunTime 두 프로세스로 나뉘어서 컴파일을 진행한다.
- Compile Time 때 byte code 컴파일러가 시간이 많이 걸리는 최적화를 미리 해두기 때문에, byte code에서 기계어로의 번역이 훨씬 빠르다.
- 실행과정(Runtime)에 컴파일을 할 수 있기 때문에 일반 인터프리터 언어에 비해 훨씬 성능이 좋다.
- JIT 컴파일러는 메서드가 컴파일되면, 해석하는 대신 직접 해당 메서드의 컴파일된 코드를 호출한다.
- 그러면 컴파일에 프로세서 시간과 메모리 사용이 필요하지 않게되어 속도가 빨라진다.
- JIT 컴파일러는 같은 코드는 캐싱해서 재사용하고, 바뀐 코드만 컴파일 한다.
- 자주 사용되는 메서드는 빨리 컴파일 되고 사용되지 않는 메서드는 거의 나중에 컴파일되거나 아예 컴파일 되지 않을 수도 있다.
6. JVM 구성 요소
JVM은 다음 그림과 같은 구조로 이루어져있다.
알아보자.
1. Class Loader
- .java 파일을 컴파일러가 .class로 변환하고 JVM의 클래스 로더에게 보낸다.
- 클래스 로더는 프로그램에서 클래스를 사용할 때 마다, 동적으로 해당 class 파일을 Runtime Data 영역으로 로딩하여 JVM의 메모리에 올린다(동적 코드 로딩 기능).
- 메모리에 로드되는 첫 번째 클래스는 일반적으로 main() 메서드가 포함된 클래스이다.
2. Runtime Data
런타임 데이터 영역에는 총 5개의 구성 요소가 하나씩 있다.
프로그램이 실행되면 JVM은 OS로부터 할당받은 메모리를 각 영역에 나누어 관리한다.
💙 Method Area (= Class Area)
- 클래스정보 (멤버변수, 생성자 등)
- 메서드 정보 (메서드 이름, 리턴타입, 파라미터, 접근제어자)
- 상수 풀 (문자상수, 타입, 필드, 객체 참조)
- 변수 정보(데이터타입, 접근제어자), static 변수 정보 저장
- JVM이 동작해서 클래스가 로딩될 때 생성되고, 종료될때까지 유지된다.
💙 Heap Area
- new 키워드로 생성되는 객체 인스턴스를 저장
- Method Area에 로드된 클래스만 생성 가능
- 참조형(class, interface, enum, Array 등) 자료형도 같이 저장
- Heap의 참조 주소는 Stack이 갖고 있고, 해당 객체를 통해서만 힙 영역에 있는 인스턴스를 핸들링할 수 있다.
- Garbage Collector의 주요 대상이며, 효율적인 GC를 위해 다음과 같이 나뉜다.
- Permanent Generation: 생성된 객체들의 정보의 주소 값이 저장된 공간
- New Area
- Eden : 객체들이 최초로 생성되는 공간
- Survivor : Eden에서 참조되는 객체들이 저장되는 공간
- Old Area : New Area에서 일정시간이상 참조되고 있는 객체들이 저장되는 공간
- Runtime 에 생성된다
💚 Stack Area
- 메소드를 호출할 때마다 각각의 스택 프레임이 생성되며, 종료 시 삭제된다.
- 메서드 안에서 사용되는 매개변수(parameter), 지역변수, 리턴값, 연산에 사용되는 임시값 등이 저장된다.
- Compile Time 에 할당된다
💛 PC Register
- JVM은 멀티 스레드를 지원하는데, 각 스레드는 JVM의 명령 주소를 저장하는 PC Register를 하나씩 갖는다.
- 현재 스레드가 실행되는 부분의 주소와 명령을 저장하는 영역으로, 명령어가 실행되면 다음 명령어로 업데이트 된다.
- 스레드가 생성될 때 마다 생성되는 공간이다.
💛 Native Method Stack
- 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역(JNI)이다.
[ 참고 : 멀티 스레드 시 공유되는 영역 ] 메서드 및 힙 영역은 여러 스레드에서 동일한 메모리를 공유하므로, 여기에 저장된 데이터는 스레드로부터 안전하지 않다. 반면 스택, PC Register, Native Method Stack은 각각의 스레드마다 생성되고 공유되지 않는다.
3. Execution Engine
- Interpreter
- 바이트코드 명령어를 한 줄씩 읽고 실행
- 메서드가 여러 번 호출될 때마다 새로 해석해야 함
- JIT Compiler
- Execution Engine은 먼저 인터프리터를 사용하여 바이트 코드를 실행하지만 일부 반복 코드를 찾으면 JIT 컴파일러를 사용한다. (인터프리터의 단점을 극복)
- Garbage Collector
- 자바의 메모리 관리 방법 중의 하나로 JVM의 Heap 영역의 동적 할당 메모리 중 참조 되지 않는 객체 메모리를 주기적으로 수집 및 제거하는 프로세스이다.
7. JDK와 JRE의 차이
앞서 자바로 작성한 프로그램을 컴파일하고 실행하기 위해 JDK를 다운로드 했었다.
- JDK(Java Development Kit :자발 개발 도구)에는 JRE, 여러 라이브러리들, javac 컴파일러 등이 포함되어 있다. 자바 어플리케이션 개발을 위해 다운로드 하는 소프트웨어 패키지인 것이다.
- JRE(Java Runtime Envorinment : 자바 실행 환경)는 기본 JVM 등 자바 프로그램 실행에 필요한 라이브러리와 소프트웨어가 포함된다.
소프트웨어 프로그램을 실행하려면 실행환경(Runtime Envorinment)이 필요하다.
Runtime 환경은 프로그램 실행을 위해 클래스 파일을 로드하고 메모리 및 기타 시스템 리소스에 대한 액세스를 확보한다.
개발할 때에는 JDK가 중요하지만, JRE는 개발 단계보다는 클라우드 및 DevOps 환경의 모니터링 및 구성에서 중요하다.
DevOps는 애플리케이션과 서비스를 빠른 속도로 제공할 수 있도록 조직의 역량을 향상시키는 문화 철학, 방식 및 도구의 조합이다.
과거에는 대부분의 SW가 OS를 Runtime 환경으로 사용했다.
해당 프로그램이 위치한 컴퓨터에서 실행됐지만 리소스(메모리,프로그램 파일, 종속성) 액세스는 OS 설정에 의존했다.
JRE는 OS 위에서 실행되면서 자바 프로그램을 위한 부가적인 서비스를 제공하는 SW 계층인데, 일종의 가상 OS로서 컴퓨터 OS를 자바 애플리케이션 실행을 위해 일관적인 플랫폼으로 추상화한다.
대부분의 컴퓨터는, 어떤 방식으로 개발되든지 간에 모든 자바 애플리케이션을 실행 할 수 있는 자바 SE용으로 개발된 JRE를 실행한다고 한다. 놀라운건 대부분의 모바일 기기에 자바 ME용 JRE가 기본적으로 설치되어 제공된다는 것이다.
참고
Java의 정석 - 남궁 성
www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jvm_components.html
www.ibm.com/support/knowledgecenter/en/SSYKE2_8.0.0/com.ibm.java.vm.80.doc/docs/jit_overview.html
ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC
ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C
'Language > Java' 카테고리의 다른 글
자바 지네릭스(Generics) (0) | 2022.10.21 |
---|---|
Java 입출력 스트림 (0) | 2022.01.10 |