본문 바로가기

WhiteShip Java Study : 자바 처음부터 멀리까지

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

선장님과 함께하는 자바 스터디입니다.

자바 스터디 Github

github.com/whiteship/live-study

 

whiteship/live-study

온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.

github.com

나의 Github

github.com/cmg1411/whiteShip_live_study

 

cmg1411/whiteShip_live_study

✍ 자바 스터디할래. Contribute to cmg1411/whiteShip_live_study development by creating an account on GitHub.

github.com

 

 

 

 

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

1. JVM 이란 무엇인가

JVM

  • Java Virtual Machine 의 약자
  • JRE 에 포함된다.
  • 자바 에플리케이션을 클래스로더를 통해 읽어들이고 자바 바이트코드를 해석하고 실행 한다.
  • 자바 실행에 필요한 메모리를 OS 로 부터 할당받는다.
  • JVM, 즉 JRE 는 OS에 따라 다르지만, JVM 위에서 돌아가는 자바 코드는 JVM 덕분에 OS에 독립적이다.

Java 이전의 C 나 C++ 같은 경우 OS가 바뀌면 작성했던 코드를 일련의 과정을 통해 OS에 맞게 다시 작성해야 했다고 한다.

하지만 JVM 은 어떤 환경에서 작성되었든 바이트코드를 해석하여 같은 결과를 낸다. 따라서 OS에 독립적이다.

또한 코틀린, Groovy 등 어떤 환경에서 작성되었든(Java 기반) 같은 바이트코드가 나오기만 하면 같은 결과를 낸다.

 

 

 

 

2. 컴파일 하는 방법

자바의 컴파일은 javac 라고 하는 자바의 컴파일러로 수행된다.

javac는 JDK에 포함되어 있으며, 우리가 작성한 .java 파일을 .class 파일인 바이트코드로 바꿔준다.

 

아래의 흐름도로 한눈에 볼 수 있다.

 

 

먼저 terminal에서 아래 명령을 통해 간단한 자바 파일을 만들어보자.

> vim hello.java

public class hello {
	public static void main(String[] args) {
    	System.out.println("hello java");
    }
}

 

만들어진 자바 파일을 컴파일하는 명령어는 아래와 같다.

javac <options> <sourcefiles(~.java)>
> javac hello.java

컴파일이 완료되고 .class 파일이 생성된다.

 

javac 에 부여할 수 있는 옵션은 대표적으로 아래와 같이 있다. (더 많음)

-classpath (-cp) javac -classpath (클래스파일경로) hello.java 컴파일을 위해 참조할 클래스 파일의 경로를 지정해주는 옵션
-target javac -target 1.2 hello.java 자바를 컴파일할 자바버전을 지정해주는 옵션
-d javac -d (경로) hello.java 클래스 파일을 생성할 경로를 지정해주는 옵션
-sourcepath javac -sourcepath (소스파일경로) 컴파일을 위해 참조할 소스 파일의 경로를 지
정해주는 옵션

classpath, sourcepath 차이 : gispilot.tistory.com/5

 

 

 

3. 실행하는 방법

javac 로 컴파일되어 만들어진 .class(바이트코드)(클래스파일) 을 실행시키는 방법은 아래와 같다.

> java <options> <file>
> java hello

 

java 옵션

-classpath java -classpath (파일 경로) hello 클래스파일의 위치를 지정하는 옵션
-version java -version 현재 JVM 의 버전을 출력

 

 

 

 

4. 바이트코드

바이트코드는 2번에서의 그림에서 javac 가 우리의 소스파일을 컴파일한 .class 파일을 말한다.

또한 JVM이 실행하게 되는 파일이다.

 

정확하게는, Java가 OS 에 독립적으로 동작하기 위하여 사용하는 사용자 언어인 JAVA와 기계어 사이의 중간 언어를 말한다.

 

바이트코드는 1byte, 즉 8bits, 즉 256개 라는 의미를 유추할 수 있다.

무엇이 256개일까.

우리가 작성한 소스코드 .java 파일이 256개의 자바 명령어로 바이트코드로써 표현되어 있다. 그래서 바이트 코드이다.

바이트코드의 각 명령어는 1바이트의 OpCode와 추가 피연산자로 이루어져 있다.

 

JVM 은 이 바이트코드를 읽어들여서 에플리케이션을 실행한다.

 

 

바이트코드(.class)의 내용을 확인할 수 있는 명령어는 아래와 같다.

> javap hello

javap 명령은 역어셈블 명령이라 한다고 한다.

역어셈블 : 클래스 파일 내부의 기본 구조와 JVM 바이너리 코드를 가지고 오는 것.

 

위를 보면 hello.class 는 hello.java 로부터 컴파일 되었으며,

안에는 어떤 클래스와 어떤 메소드가 있는지 보여준다.

클래스 내부의 상수와 함수들의 목록을 간단히 보여주는 명령이다.

 

-c 옵션을 붙이게 되면 역어셈블한 결과를 바이트 코드와 함께 보여준다.

 

 

 

 

5. JIT 컴파일러

JVM 이 바이트코드를 읽어들여 실행하는 방식은 기본적으로 Interpreter 방식이었다.

 

인터프리터 방식은 바이트코드 명령어를 하나하나 읽어서 실행하는 방식이다.

하나하나 해석하여 실행하는 방식은 C 나 C++에 비해 Java 가 실행속도가 느리다 라는 말을 나오게한 이유였다.

 

하지만 JIT 컴파일러를 JVM 에 들이면서 Java는 빠른 언어로 거듭났다.

 

JIT (Just In TIme) 컴파일러는 런타임시 전체 바이트코드를 기계어로 한번에 컴파일한다.

바이트코드를 인터프리터방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 네이티브코드(기계어) 로 만든다.

이후 컴파일 된 기계어를 캐싱해두고, 반복되는 내용이 나오면 캐싱한 내용을 바로 사용하기에 속도가 빠르다.

 

 

 

 

6. JVM 구성 요소

JVM 의 동작을 전체적인 그림을 그리자면 위와 같다.

클래스 로더(Class Loader)가 컴파일된 자바 바이트코드를 런타임 데이터 영역(Runtime Data Areas)에 로드하고, 실행 엔진(Execution Engine)이 자바 바이트코드를 실행한다.

 

  • Class Loader : 바이트코드를 읽어들여 런타임 데이터 영역에 로드한다. 바이트코드를 읽어들일때, 동적 로드 방식을 사용하는데, 컴                           파일타임에 클래스를 한꺼번에 로딩하는 것이 아니라 런타임에 클래스를 처음으로 참조할 때 해당 클래스를 로딩하는                         이다.
  • Execution Engine : 자바 바이트코드를 실행한다. 하나의 OpCode를 피연산자와 함께 가져와서 실행하고, 다음 OpCode를 가져오는                                 식으로 동작한다.
    • Interpreter
    • JIT
    • GC (Garbage Collector) : 사용자가 메모리 관리를 하지 않아도 되는 이유이다. 사용하지 않는 객체를 찾아서 메모리에서 해제한                                          다.
  • Runtime Data Area : JVM 이 운영체제 위에서 실행되면서 운영체제에게서 할당받는 메모리 영역
    • Method Area : 모든 스레드가 공유하는 영역. 런타임 상수 풀, 필드와 메서드 정보, static 변수, 메서드의 바이트코드 등을 저장
    • heap : 인스턴스, 객체를 저장하는 영역. 가비지 컬렉션의 대상이다.
    • Thread : 쉽게말해 하나의 스레드는 하나의 메서드가 실행될 때 생긴다.
      • PC Register : 수행중인 JVM 명령의 주소
      • Stack : 메소드의 지역변수처럼 스레드의 일시적인 자원을 push, pop하는 영역
      • Native Method Stack : JNI(Native Method Interface) 를 통해 호출하는 C/C++ 등의 코드를 수행하기 위한 스택 

 

 

 

7. JDK, JRE 차이

 

  • JRE : 자바 에플리케이션을 실행하기 위한 도구
  • JDK : 자바 어플리케이션을 개발하기  위한 도구, JRE 를 포함한다.

 

 

 

참고 : d2.naver.com/helloworld/1230

'WhiteShip Java Study : 자바 처음부터 멀리까지' 카테고리의 다른 글

클래스  (0) 2021.01.30
4주차) 과제  (0) 2021.01.30
제어문  (0) 2021.01.28
연산자  (0) 2021.01.28
자바 데이터 타입, 변수 그리고 배열  (0) 2021.01.16