본문 바로가기

JAVA/온라인 스터디

1주차 JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.

Java Logo

목표

자바 소스 파일(.java)을 JVM으로 실행하는 과정 이해하기.

 

학습할 것

1. JVM이란 무엇인가 

2. 컴파일 하는 방법 

3. 실행하는 방법 

4. 바이트코드란 무엇인가 

5. JIT 컴파일러란 무엇이며 어떻게 동작하는지

6. JVM 구성 요소 

7. JDK와 JRE 차이 


1. JVM이란 무엇인가?

JVM은 (Java Virtual Machine)의 약어이다. JVM은 작성한 코드를 실행했을 때, 결과를 보여주는 가상 머신이다. (중간에 많은 과정이 생략되었지만, 추후 보충 설명하겠다. 지금은 간단하게 이해만 하자.) 이는 자바의 실행방법을 보면 조금 더 이해가 쉽다. 

JAVA 실행 방법 (출처: https://opentutorials.org/course/1223/5559)

그림 중간에 컴파일러는 인간어 (소스코드)를 컴퓨터가 이해하는 언어로 바꿔주는 개념으로 이해하면 된다. 여기서 중요한 것은 JVM은 작성한 코드의 실행 결과를 보여주는 것이며, 이외에도 다른 역할들을 수행한다. 

 

JVM의 설명을 다른 블로거들의 표현을 인용하여 설명하면 다음과 같다. 

자바 가상 머신(Java Virtual Machine, JVM)은 시스템 메모리를 관리하면서 자바 기반 어플리케이션을 위해 이식 가능한 실행 환경을 제공한다. (출처: velog.io/@dnjscksdn98/Java-What-is-JVM)
 A Java virtual machine (JVM) is a virtual machine that enables a computer to run Java programs as well as programs written in other languages that are also compiled to Java bytecode. (출처: https://en.wikipedia.org/wiki/Java_virtual_machine)

번역: 자바 가상 머신 (JVM)은 컴퓨터가 자바 프로그램과 Java bytecode로 컴파일된 다른 언어로 작성된 프로그램을 실행할 수 있도록 하는 가상 머신이다. (출처: 나)

 

즉, JVM은 컴퓨터가 프로그램을 실행할 수 있도록 하는 가상 머신이라고 이해하면 편하다. 

 

 

 

참고 자료 모음

1. velog.io/@dnjscksdn98/Java-What-is-JVM

2. opentutorials.org/course/1223/5559 

3. https://en.wikipedia.org/wiki/Java_virtual_machine


2. 컴파일 하는 방법

컴파일 하는 방법을 설명하기 전에 컴파일에 대해 설명하겠다. 컴파일(Compile)이란, 사람이 작성한 코드를 컴퓨터가 이해를 할 수 있도록 변환을 해주는 과정을 일컫는다. 이렇게 컴파일을 하는 장치를 컴파일러(Compiler)라고 부른다. Java언어 또한 코드를 짜면, 컴파일 과정이 필요하다. 그러면 컴파일은 어떻게 하고, Java에서 사용하는 컴파일러는 무엇일까?

 

Java에서 컴파일 하는 방법은 다음과 같다.  

1) cmd 이용하기

 

1) cmd를 이용하여 Java 컴파일 하기

Java는 컴파일을 하기 전, 환경 변수를 설정해야 한다. 환경 변수란, 운영체제가 참조하는 변수이다. 즉 운영체제에 없는 외부 명령어를 수행해야 할 경우 환경 변수를 참조해서 실행할 수 있다. 물론, 환경 변수 없이도 외부 명령어를 실행할 수 있지만, 이럴 경우에는 해당 명령어에 실행 파일이 있는 위치까지 경로를 이동해주어야 한다. 

 

보다 더 자세한 설명은 cmd를 이용해 Java 컴파일을 하는 과정을 통해 설명하겠다. 

 

(1) 환경 변수 등록 (Win 10 기준)

제어판 - 시스템 - 시스템 환경 변수 편집 선택

 

JAVA_HOME 등록을 위해 새로 만들기 버튼 클릭

 

JAVA가 설치된 파일 경로 (디렉터리 찾아보기로 선택) - jdk 파일 선택하면 끝
시스템 변수에서 Path 검색 후 편집 클릭
새로 만들기 - %JAVA_HOME%\bin; - 확인

(2) cmd 창에서 javac 입력

(3) javac 관련하여 여러 영어 보이면 정상적으로 작동

(4) 자바 소스코드 작성 후 javac (파일명).java 입력시 컴파일이 된다. 

(5) class 파일이 생성 되면 컴파일 완료.

 

 

참고 자료 모음

1. opentutorials.org/course/1223/5559

2. m.blog.naver.com/10hsb04/221613745124

3. blog.naver.com/10hsb04/221572640230

4. tocomo.tistory.com/3

5. light-tree.tistory.com/6

6. dololak.tistory.com/20

7. amikhs.pe.kr/?c=1&uid=626

8. anatomylab.tistory.com/8

 


3. 실행하는 방법

컨파일을 한다고 해서 작성한 소스 코드는 즉각적으로 확인할 수 없다. 이를 실행을 해야 한다. 실행을 하기 위해서는 java 명령어를 활용해 파일명에서 확장자명(.class)을 제거하고, 입력 하면 된다. 

 

구체적으로 실행 방법은 다음과 같다. 

1) Java 소스 코드 작성

2) 컴파일러를 통해 컴파일을 한다. 

3) 바이트 코드 생성 

4) 바이트 코드를 java 명령어 (실행 명령어)를 통해 실행한다. 

5) 실행 결과 


4. 바이트 코드란 무엇인가

바이트 코드 (Bytecode, portable code, p-code)
특정 하드 웨어가 아닌 가상 컴퓨터에서 돌아가는 실행 프로그램을 위한 이진 표현법이다. 
하드웨어가 아닌 소프트웨어에 의해 처리되기 떄문에 기계어보다 추상적이라고 한다. (위키피디아)

 

자바 바이트 코드(Java bytecode)란 자바 가상머신이 이해할 수 있는 언어로 변환된 자바 소스 코드를 의미한다. 
자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 1바이트라서 자바 바이트 코드라고 불린다. 
이러한 자바 바이트 코드의 확장자는 .class입니다. 
자바 바이트 코드는 자바가상 머신만 설치되어 있다면, 어떤 운영체제에서라도 실행될 수 있다. 

 

 

참고자료모음

1. tcpschool.com/java/java_intro_programming

2. ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C


5. JIT 컴파일러란 무엇이며 어떻게 동작하는지

JIT 컴파일 또는 동적번역(dynamic translation)은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법이다. 자바 가상머신, .NET, V8(node.js)에서는 JIT 컴파일을 지원하다. 즉, 자바 컴파일러가 자바 프로그램 코드를 바이트 코드로 변환한 다음, 실제 바이트 코드를 실행하는 시점에서 자바 가상 머신이 바이트 코드를 JIT 컴파일을 통해 기계어로 변환한다. 

 

컴퓨터 프로그램을 만드는 방식은 두 가지이다. 

1. 인터프리트 방식(실행 중 프로그래밍 언어를 읽어가면서 해당 기능에 대응하는 기계어 코드 실행)

2. 정적 컴파일 방식(실행하기 전에 프로그램 코드를 기계어로 번역)

 

실행 시점에서 인터프리트 방식으로 기계어 코드를 생성하면서 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 기계어 코드를 생성하는 것을 방지한다. (즉 이후에, 바뀐 부분들만 컴파일하고 나머지 캐싱된 코드를 사용하여 인터프리터의 속도를 개선할 수 있다.)

 

참고자료모음

1. ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC

2. medium.com/@ahn428/java-jit-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC-c7d068e29f45


6. JVM 구성 요소 

JVM은 Java Virtual Machine 의 약자이다. 이는 다음과 같이 구성되어 있다. JVM은 

 

출처: https://odol87.tistory.com/5

클래스 로더가 바이트코드를 런타임 데이터 영역에 로드하고, 실행 엔진이 바이트코드를 실행하는 구조이다. 

 

1) 클래스 로더

자바는 동적로드(레이지 로딩, 인터프리터, JIT)라는 특징이 있다. 컴파일 타임에 필요한 클래스들을 로딩하는 것이 아니라 런타임에 클래스를 처음 참조할 때 해당 클래스를 로드하고 링크하는 방식을 취한다. 이 동적 로드를 담당하는 부분이 JVM의 클래스 로더이다. 

 

2) 런타임 데이터 영역

출처: https://odol87.tistory.com/5

런타임 데이터 영역은 JVM이라는 프로그램이 운영체제 위에서 실행되면서 할당받는 메모리 영역이다. 위의 PC 레지스터, JVM 스택, 네이티브 메서드 스택은 스레드마다 하나씩 생성되며 힘과 메서드 영역(런타임 상수 풀)은 모든 스레드가 공유한다. 

 

3) PC 레지스터

PC(Program Counter) 레지스터는 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다. PC 레지스터는 현재 수행 중인 JVM 명령의 주소를 갖는다. 

 

4) JVM 스택

VM 스택은 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다. 스택 프레임(Stack Frame)이라는 구조체를 저장하는 스택으로, JVM은 오직 JVM 스택에 스택 프레임을 추가하고(push) 제거하는(pop) 동작만 수행한다. 예외 발생 시 printStackTrace() 등의 메서드로 보여주는 Stack Trace의 각 라인은 하나의 스택 프레임을 표현한다. 

5) 스택 프레임

JVM 내에서 메서드가 수행될 때마다 하나의 스택 프레임이 생성되어 해당 스레드의 JVM 스택에 추가되고 메서드가 종료되면 스택 프레임이 제거된다. 각 스택 프레임은 지역 변수 배열(Local Variable Array), 피연산자 스택(Operand Stack), 현재 실행 중인 메서드가 속한 클래스의 런타임 상수 풀에 대한 레퍼런스를 갖는다. 지역 변수 배열, 피연산자 스택의 크기는 컴파일 시에 결정되기 때문에 스택 프레임의 크기도 메서드에 따라 크기가 고정된다. 

 

6) 지역 변수 배열

0부터 시작하는 인덱스를 가진 배열이다. 0은 메서드가 속한 클래스 인스턴스의 this 레퍼런스이고, 1부터는 메서드에 전달된 파라미터들이 저장되며, 메서드 파라미터 이후에는 메서드의 지역 변수들이 저장된다. 

 

7) 피연산자 스택

메서드의 실제 작업 공간이다. 각 메서드는 피연산자 스택과 지역 변수 배열 사이에서 데이터를 교환하고, 다른 메서드 호출 결과를 추가하거나(push) 꺼낸다(pop). 피연산자 스택 공간이 얼마나 필요한지는 컴파일할 때 결정할 수 있으므로, 피연산자 스택의 크기도 컴파일 시에 결정된다. 

8) 네이티브 메서드 스택

자바 외의 언어로 작성된 네이티브 코드를 위한 스택이다. 즉, JNI(Java Native Interface)를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택으로, 언어에 맞게 C 스택이나 C++ 스택이 생성된다. 

9) 메서드 영역

메서드 영역은 모든 스레드가 공유하는 영역으로 JVM이 시작될 때 생성된다. JVM이 읽어 들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메서드 정보, Static 변수, 메서드의 바이트코드 등을 보관한다. 메서드 영역은 JVM 벤더마다 다양한 형태로 구현할 수 있으며, 오라클 핫스팟 JVM(HotSpot JVM)에서는 흔히 Permanent Area, 혹은 Permanent Generation(PermGen)이라고 불린다. 메서드 영역에 대한 가비지 컬렉션은 JVM 벤더의 선택 사항이다. 

 

10) 런타임 상수 풀

클래스 파일 포맷에서 constant_pool 테이블에 해당하는 영역이다. 메서드 영역에 포함되는 영역이긴 하지만, JVM 동작에서 가장 핵심적인 역할을 수행하는 곳이기 때문에 JVM 명세에서도 따로 중요하게 기술한다. 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블이다. 즉, 어떤 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조한다. 

 

11) 힙

인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션 대상이다. JVM 성능 등의 이슈에서 가장 많이 언급되는 공간이다. 힙 구성 방식이나 가비지 컬렉션 방법 등은 JVM 벤더의 재량이다.

 

참고자료모음

1. odol87.tistory.com/5


7. JDK와 JRE 차이 

JRE(Java Runtime Envrionment)는 자바 런타임 환경, JVM (Java Virtual Machine), Java 클래스 라이브러리, Java 명령 및 
기타 인프라를 포함하여 컴파일 된 Java 프로그램을 실행하는 데 필요한 모든 패키지이다. 새 프로그램을 작성하는 데 사용할 수 없다. 

JDK (Java Development Kit) 자바의 모든 기능을 갖춘 SCK, JRE의 모든것(ex javac) + 컴파일러 및 도구(javadoc, jdb)를 프로그램을  작성하고 컴파일 할 수 있다.  

Java 프로그램을 실행할 경우 JRE만 있으면 된다. Java 프로그래밍을 해야할 경우 JDK를 설치해야 한다. 
JSP 를 사용하여 웹 응용 프로그램을 배포할 경우 기술적으로 응용 프로그램 서버 내에서 Java 프로그램을 실행한다. 
이때, 애플리케이션 서버가 JSP 를 Java 서블릿으로 변환하고 서블릿을 컴파일하기 위해 JDK를 사용하다. 

JDK = JRE + 개발 / 디버깅 툴
JRE = JVM + Java 패키지 클래스 (유틸리티 수학, lang, awt, 스윙 등)+ 런타임 라이브러리
JVM = 클래스 로더 시스템 + 런타임 데이터 영역 + 실행 엔진 

JRE (Java Runtime Envrionment) Java 프로그래밍 언어로 작성된 애플리케이션 및 응용 프로그램을 실행하기 위한 라이브러리, Java Virtual Machine 및 기타 구성 요소를 제공한다. 

참고자료모음

1. 


 

'JAVA > 온라인 스터디' 카테고리의 다른 글

[4주차] 제어문 #4  (0) 2020.12.10
[3주차] 연산자  (0) 2020.11.27
2주차 라이브 방송 정리  (0) 2020.11.22
2주차 자바 데이터 타입, 변수 그리고 배열  (0) 2020.11.21
1회차 피드백 정리  (0) 2020.11.17