본문 바로가기
프로그래밍 언어

자바 1주차 스터디

by do_ng 2021. 2. 16.

목차

  • JVM란 무엇인가?
  • 컴파일하는 방법
  • 바이트코드란 무엇인가?
  • JIT컴파일러란 무엇이며 어떻게 동작하는가 
  • JVM 구성요소
  • JDK와 JRE 차이 

 

JVM란 무엇인가?

정의 : 자바로 만들어진 프로그램(바이트코드로 컴파일된)을 실행할수 있는 자바가상머신  

 

실행흐름)

 

자바로 작성한 소스파일(.java)은 자바 컴파일러를 통해 .class 확장자를 가지는 바이트코드로 컴파일이 되며 

JVM은 컴파일된 .class 파일을 해당 운영체제에 맞춰서 기계어로 번역을 함  

※ JDK에 있는 자바 컴파일러는 JVM이 이해할 수 있는 바이트코드로 변환을 해주는 컴파일러임 기계어로 번역하는 컴파일러와는 다른 컴파일러임 

 

출처 : https://dololak.tistory.com/327

 

JVM 특징)

- JVM은 바이트코드를 기계어로 번역해 실행을 하는데 자바소스를 컴파일해서 만든 바이트코드 뿐만아니라

C#을 컴파일해서 만든 바이트코드도 JVM에서 실행이 가능한가? 

( C#을 컴파일해서 만든 바이트코드가 JVM에서 돌아가는가?? 의문점이 생김) 

 

- C언어로 작성된 프로그램 같은 경우 OS에 종속적이기 때문에 OS위에서 실행되는 반면에 자바로 작성된 프로그램은 JVM에서 바이트코드를 기계어로 번역하는 과정과 해당 OS에서 번역된 기계어를 실행하는 크게 두단계의 과정을 거쳐가기 때문에 OS에서 직접 제어받는 방식보다 속도면에서 느리다고 하지만 JIT(Just In Time)컴파일러를 통해 속도차이를 극복함 

 

컴파일 하는 방법

보통은 이클립스나 인텔리제이 같은 IDE를 사용해서 손쉽게 컴파일을 할 수 있지만 직접 컴파일을 해보자

 

1. 메모장을 통해 자바코드 작성 (확장자는 .java) 

 

2. cmd(명령 프롬프트)를 통해 Hello.java가 있는 경로로 이동후 컴파일 하기

(환경변수 설정이 되어있기 때문에 어느 경로에서 실행하던 컴파일 가능

#환경변수가 설정이 안되어 있으면 JDK가 있는 경로에서 실행을 해야지 컴파일이 가능)

 

3. 컴파일된 Hello.class 파일 (JVM이 해석할 수 있는 바이트코드)

가상 컴퓨터에서 실행될수 있게끔 이진표현법으로 변경된 언어

 

4. 컴파일된 클래스파일(Hello.class)를 실행

 

바이트 코드란?

정의 : 해당 프로그램이 가상 컴퓨터에서 돌아가기 위해 이진표현법으로 작성된 것

(자바코드가 컴파일러에 의해서 JVM이 이해할 수 있는 언어로 변환된 것이라고 이해를 하자) 

 

자바 문법으로 작성된 .java 파일은 컴퓨터가 이해할 수 없기 때문에 컴퓨터가 이해할 수 있도록 만들어 줘야 된다.

컴퓨터가 이해할 수 있는 형태로 번역을 하기전에 자바 컴파일러에 의해서 바이트코드로 변환이 된후 JVM이 .class 확장자를 가지는 바이트코드를 Interpreter를 통해 기계가 읽을 수 있는 형태(Native Code)로 변환이된다. 

 

JIT 컴파일러란 무엇이며 어떻게 동작하는가?

기존에는 클래스파일(바이트코드)를 Interpreter방식으로 실행하였다. 

Interpreter 방식은 명령어를 하나씩 해석해서 처리하기 때문에 하나하나씩 처리하는게 빨라보일수도 있지만 코드의 양또는 반복되는 코드가 많아진다면 전체적으로 봤을때 실행속도가 떨어지게 된다. 

 

이러한 실행속도를 개선하기 위해서 같은 코드를 매번 새롭게 Interpreter 방식으로 해석하는 대신, 실행하기 전에 미리

JIT 컴파일러를 이용해서 "반복적인 코드"를 "네이티브 코드(기계가 읽을수 있는 형태)"로 전부 바꿔두고 그 다음부터는

인터프리터가 변환된 네이티브 코드들 바로 사용함으로써 인터프리터 방식으로만 해결했을때의 문제점을 개선할 수 있다.

 

그러나 JIT 컴파일러가 컴파일하는 과정은 바이트코드를 하나씩 인터프리팅하는 것보다 훨씬 오래 걸리므로 초기 실행속도와 메모리 사용량 면에서 손해를 보는 단점도 있다.

따라서, JIT 컴파일러를 사용하는 JVM은 내부적으로 해당 메서드가 얼마나 자주 실행되는지 체크하고, 그에 따라 JIT 컴파일러를 사용했을때 속도면에서 효율적이라면 JIT컴파일러를 사용한다. 

 

출처 : https://github.com/Chohongjae/javaStudy/blob/main/live-study/week1.md

 

 

JVM 구성 요소 

JVM의 구조까지 파악하고 이해하기에는 시간이 걸린다.. 까먹으니까 지금은 이런게 있다라고 알아두자 

 

 

JDK와 JRE 차이 

출처 : https://gblee1987.tistory.com/173

 

JDK는 JRE + 개발을 하기위해 필요한 도구들(Compilers,Debuggers..등)이 있고 

JRE는 JVM + 각종 라이브러리들이 포함되어 있다. 

 

 

추가적인 사항

 

자바의 버전 호환 문제)

 

Java 버전 11로 컴파일한 자바 프로그램 -> Java 8 버전에서는 실행이 안됨

(상위 버전에서 컴파일한 자바 프로그램을 하위 버전에서 실행이 불가능) 

 

컴파일 하기전에 옵션을 줘서 상위버전에서 컴파일을 했어도 하위 버전에서 실행가능하도록 할 수 있음(찾아보기) 

 

컴파일 타임 vs 런타임 ) 

 

컴파일 타임 : 작성된 Java 코드를 .class 파일로 컴파일하는 과정

 

컴파일 타임에러 : 소스코드가 컴파일되는 중에 Syntax Error,Type check Error 같은 문제들로 인해 발생하는 오류

public class Main {

	public static void main(String[] args) {
		
		int a = "Hello"; // 컴파일하는중 여기서 타입 에러발생 
			
	}

}

컴파일 도중 타입에러가 발생하기 때문에 .class 파일을 만들지 않음 

(프로그램 실행전에 오류를 잡아낼수 있다는 점에서 오류를 사전에 방지할 수 있다는 장점이 있음) 

 

 

런타임 : 컴파일된 소스코드가 실행되는 동안을 뜻함

배틀그라운드라는 게임엔진으로 비유를 들자면 해당 게임을 하는데 필수적인 요소들(자동차 수량,적과 아군의 능력치,지도정보)들은 게임엔진에 담겨져 있지만 무조건 적이 이곳에 있다라는 정보들은 담겨져 있지 않음

종합하자면 해당 엔진을 사용하는 동안 사용자의 행동에 따라서 데이터가 변경될 수 있다라는 것임  

 

런타임 에러 : 컴파일이 완료되어 프로그램이 실행하는 동안 의도치 않은 예외상황(메모리부족,null값..등등)으로 인하여 발생하는 오류 

public class Main {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		int key = sc.nextInt();
		
		switch (key) {
		case 0:
			System.out.println(key/0);
			break;
		case 1:
			System.out.println(key/1);
			break;
		default:
			break;
		}
			
	}

}

컴파일이 정상적으로 완료(.class 파일 생성)되고 프로그램이 실행되는데 사용자가 1을 입력하게 되면 1을 출력하지만 0을 입력하면 오류가 발생하게 된다. 

컴파일 에러와 같이 사전에 오류를 방지하기가 힘들기 때문에 직접 코드를 뜯어봐야된다는 수고가 든다. 

 

컴파일러 vs 인터프리터 )

 

인터프리터 : 코드를 한줄씩 읽어 내려가며 실행하는 프로그램으로 소스코드를 한줄씩 읽고 기계어로 번역을 하기 때문에 반복되는 메서드 또는 코드의 양이 많아지면 속도가 저하됨 이를 해결하기 위해 반복적으로 쓰이는 함수와 클래스 등의 기계어 코드를 캐싱하는 JIT 컴파일러를 인터프리터에 내장하는 방식을 통해 속도차이를 극복함 

 

컴파일러는 소스코드를 전체를 번역한다음 실행파일을 만들기 때문에 프로그램에 수정사항이 발생하면 소스코드를 다시 컴파일 해야되는데 만약 프로그램의 용량이 크다면 컴파일을 하는데만 해도 시간이 오래걸린다. 

하지만 인터프리터는 해당 소스코드만 수정해서 기계어로 번역을 해주면 되기 때문에 수정이 빈번하게 일어나는 용도의 프로그래밍에서 많이 사용됨 

 

컴파일러 : 인터프리터가 코드를 한줄 읽고 기계어로 번역하는 통역기라면 컴파일러는 전체의 코드를 읽고 한꺼번에 번역을 해주는 번역기라고 이해를 하면 쉽다. 

 

참고 : namu.wiki/w/%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC

 

용어정리)

  • Interpreter 방식 : 명령어를 하나씩 수행하는 방식(삼겹살 3줄이 있다고 하면, 1줄굽고 먹고 1줄굽고 먹고 하는 방식)
  • JIT(Just In Time Compiler) : 전체 바이트코드를 네이티브 코드로 변환후 그 이후에는 네이티브 코드로 실행하는 방식(삼겹살 3줄을 구워놓고 먹는 방식) 

'프로그래밍 언어' 카테고리의 다른 글

디버거 사용하기  (0) 2021.02.21
자바 2주차 스터디  (0) 2021.02.18
다형성  (0) 2021.02.12
추상클래스 , 인터페이스 개념  (0) 2021.01.28
배열 vs 리스트  (0) 2021.01.26