2022-01-26 작성

자바의 구동 원리와 JVM(Java Virtual Machine)

자바 프로그램의 구동 원리

  1. 소스코드를 작성한다. (.java 확장자의 소스 파일)
  2. 컴파일러(javac.exe)가 바이트코드로 변환한다. (.class 확장자의 클래스 파일)
  3. 런처(java.exe)로 자바 가상 머신을 구동시킨다.
  4. 자바 가상 머신이 바이트코드를 해석하여 자바 프로그램이 실행된다.

위 순서에서 바이트코드(bytecode)는 자바 가상 머신이 이해할 수 있는 언어로 변환된 코드다. 자바 가상 머신만 설치되어 있다면 바이트코드는 어떤 운영체제에서라도 실행될 수 있다.

자바 가상 머신(JVM)

일반 프로그램은 "운영체제"가 프로그램을 실행시킨다. 반면 자바 프로그램은 운영체제가 JVM을 실행시키면 "JVM"이 프로그램(클래스 파일)을 실행시킨다. 

즉, 자바 프로그램의 클래스 파일들은 운영체제에서 직접 동작하는 것이 아니라 "JVM" 위에서 동작한다. 그래서 윈도우에서 개발한다면 윈도우용 가상 머신을 설치하고 맥에서 개발한다면 맥용 가상 머신을 설치하는 등의 운영체제용 가상 머신만 설치가 되어 있다면 자바 프로그램은 한 번 만들기만 하면 윈도우든 리눅스든 맥이든, 어느 운영체제든 실행할 수 있다. (=플랫폼 독립성, 이식성이 높다) 

다만, 플랫폼 독립성에 따라 각 운영체제에 맞는 가상 머신을 설치해야 하므로 운영체제에 종속적이다. 그리고 자바 프로그램은 일반 프로그램보다 한 단계를 더 거쳐야 하므로 상대적으로 실행 속도가 느리다는 단점이 있다.

왜 자바 가상 머신(JVM) 구조를 알아야 하는가?

출처 : ttp://stophyun.tistory.com/37

백문이 불여일견. 위 사진을 보면 정보시스템의 성능저하 요인 중 무시 못 할 수치로 JVM 및 메모리 문제가 보인다. 시스템의 성능을 높이기 위해 자바 가상 머신의 구성과 메모리를 아는 것은 자바 개발자로서 필수적인 일이다. 특히나 메모리는 사용할 수 있는 공간이 한정되어 있기에 어떻게 관리하느냐에 따라 프로그램의 성능이 좌우된다. 따라서 메모리를 효율적으로 사용하기 위해서는 메모리의 구성과 각 특징에 대해서 이해할 필요가 있다.

자바 가상 머신의 구성

출처 : http://gurubee.tistory.com/14

  • 클래스 로더(Class Loader) : 런타임 시 클래스 파일들을 JVM 내부로 로딩하고, 클래스 파일을 분석한 뒤에 각각 런타임 데이터 영역에 배치한다. 자바는 동적으로 클래스를 읽어오므로(동적 로딩) 런타임 시점에서야 모든 코드가 JVM과 연결된다. 
  • 런타임 데이터 영역(Runtime Data Areas) : 클래스 로더에서 분석된 클래스 파일의 데이터를 저장하고 실행 도중에 필요한 데이터를 저장한다. 메모리를 효율적으로 관리하기 위해 크게 5개의 영역(스태틱, 힙, 스택, PC 레지스터, 네이티브 메서드 스택)으로 구분하며, 간단히 메모리 영역이라고 부른다.
  • 실행 엔진(Execution Engine) : 런타임 데이터 영역에 배치된 바이트코드를 해석하며 실행한다. 이 때 인터프리터 방식과 JIT 컴파일 방식을 혼합하여 해석한다.
    • 인터프리터(Interpreter) 방식 : 바이트코드를 한 줄씩 읽고 해석한다.
    • JIT 컴파일(Just-In-Time compile) 방식 : 바이트코드를 런타임 시점에 바로 기계어로 변환한다.
    • 최초의 가상 머신은 인터프리터 방식만 써서 실행 속도가 느렸지만, JIT 컴파일 방식을 추가하여 이를 보완하고자 했다. 그런데 JIT 컴파일은 바이트코드를 기계어로 바꾸기 때문에 실행 속도가 빠르지만 변환하는 데 비용이 발생하게 된다. 그래서 인터프리터 방식을 사용하다가 일정한 기준이 넘어가면 JIT 컴파일 방식으로 실행한다.
  • 가비지 컬렉터(Garbage Collector)
    때에 따라 가비지 컬렉터가 메모리 관리 기능을 자동으로 수행한다. 더 이상 사용되지 않는 객체를 해제시켜 메모리를 자동으로 반납한다.

자바의 메모리 영역

런타임 데이터 영역은 실제 클래스 파일들이 배치되는 곳으로, 자바 프로그램을 실행하기 위해서 가상 머신(JVM)이 운영체제로부터 메모리에 데이터 및 명령어를 저장할 공간을 할당받는 곳이다. 5개의 영역으로 분류되지만 주로 메서드, 힙, 스택 영역이 언급된다.

 메모리 영역  용도   보존기간   스레드 공유 
 메서드
   = 클래스
   = 스태틱
  • 가장 먼저 데이터가 저장되는 공간
  • 클래스 로더에 의해 로딩된 클래스, 메서드, 클래스변수(static), 전역변수가 저장됨
  • 클래스변수나 전역변수를 무분별하게 많이 사용하면 메모리가 부족할 수 있음
  • 프로그램의 시작부터 종료까지 메모리에 남는다.
  • 명시적인 Null 선언시 GC 청소대상
 모든 스레드
 공유
 힙
  • 런타임 시 결정되는 참조형 데이터타입이 저장되는 공간
  • new 연산자를 통해 생성된 객체가 저장되는 공간
  • 객체가 더 이상 안쓰이거나, 명시적인 Null 선언시 GC 청소대상
 스택
  • 컴파일 시 결정되는 기본형 데이터타입이 저장되는 공간
  • 지역변수, 매개변수, 리턴값, 참조변수 등이 저장됨
  • 메서드 호출될 때, 메모리에 FILO로 하나씩 생성
  • 메서드 끝날 때, 메모리에 LIFO로 하나씩 제거
  • 메서드 호출시마다 각각의 스택프레임(그 메서드만의 방)이 생성
  • { } 또는 메서드가 끝날 때까지 (끝날 땐 프레임별로 삭제)
 각 스레드별
 
 PC 레지스터
  • JVM이 수행할 명령어의 주소를 저장하는 공간
  • 스레드가 시작될 때마다 생성
 네이티브 
 메서드 스택
  • 바이트코드가 아닌, 기계어로 작성된 코드를 실행하는 공간
  • 다른 언어(C/C++)로 작성된 코드를 수행하기 위함
  • Java Native Interface를 통해 바이트코드로 변환됨
  • Java Native Interface 호출 및 종료시 생성

그림으로 살펴보는 메모리

 

 

References