[Java] JVM이란?

이신영·2024년 5월 29일
1

Java

목록 보기
3/11
post-thumbnail
post-custom-banner

자바의 슬로건은 “한 번 프로그래밍 한 것은 어떤 플랫폼에서도 실행된다(Write Once, Run Anywhere)”이다.

갑자기 왜 말했냐고? JVM이 그걸 해주기 때문이다 !


JVM이란?

JVM은 자바와 운영체제(OS) 사이에서 일종의 중개자 역할을 수행하여 운영체제에 구애받지않고 독립적으로 구동이 가능한 가상 머신이다. 주 역할로는 메모리관리를 수행한다.(GC)

GC?

GC(Garbage Collection)는 자바 애플리케이션에서 사용하지 않는 메모리를 자동으로 수거하는 기능을 말한다.
= Heap영역에 배치된 객체를 관리해준다.

그래서 왜 독립적으로 쓸 수 있을까?

일반적으로 프로그램은 특정 운영 체제에 종속적으로 개발된다. 예를 들어, C++로 작성된 프로그램은 특정 운영 체제나 하드웨어에서 실행되기 위해 컴파일된다. 그러나 자바 프로그램은 먼저 바이트 코드(byte code)로 컴파일된다.

.java파일 → 컴파일 → .class(바이트 코드)

바이트 코드가 .class 파일 형태로 저장된 후, JDK의 자바 컴파일러(javac)를 사용하여 컴파일되면, 이 바이트 코드는 JVM이 이해할 수 있는 기계어로 변환된다. 이러한 변환은 JRE의 일부인 JVM에서 이루어진다.

그래서 VM은 왜쓰는 걸까?

제일 큰 이유는 OS마다 독립적으로 쓸 수 있다는것이고 쓰기편해진다 라는 거겠다. 굳이 단어로 정리하자면?

장점

1. 플랫폼 독립성
JVM은 플랫폼에 독립적이므로 한 번 작성된 코드를 여러 운영 체제에서 실행할 수 있다.

2. 메모리 관리
JVM은 가비지 컬렉션(GC)을 통해 메모리를 자동으로 관리해준다. = 메모리 누수 방지가 자동

3. 보안
JVM은 바이트 코드를 실행하기 전에 링크과정에서 검증을 수행하여 악의적인 코드의 실행을 방지해준다.

4. 풍부한 생태계
자바 생태계에는 수많은 라이브러리와 프레임워크가 존재한다. 예를 들어, 스프링 프레임워크, Hibernate, Apache Commons 등

단점

1. 속도
VM을 거쳐 코드를 실행하는 것은 일반적으로 직접 하드웨어에서 코드를 실행하는 것보다 느리다. 그러나 최적화 기술이 발전함에 따라 이 차이는 점점 줄어들고 있다.

2. 자원 사용
VM은 자체적인 운영 체제와 런타임 시스템을 유지하기 때문에 추가적인 메모리와 CPU 리소스 자원을 사용하게 된다.

딱 한줄로 요약하자면

이식성플랫폼 독립성이 높다는 장점을 보인다. 또한 GC를 사용하기때문에 메모리관리가 편하다는 점도 있다.


JVM의 구조

동작(JIT) 과정

  1. 솔루션 빌드 : 자바로 개발된 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당한다.
  2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트코드(.class)로 컴파일한다.
  3. 클래스 로딩 : Class Loader를 통해 JVM Runtime Data Area로 로딩한다.
  4. JIT 컴파일 : Runtime Data Area에 로딩 된 .class들은 Execution Engine을 통해 해석한다.
  5. Garbage Collection : 해석된 바이트 코드는 Runtime Data Area의 각 영역에 배치되어 수행하며 이 과정에서 Execution Engine에 의해 GC의 작동과 스레드 동기화가 이뤄진다.

클래스 로더(Class loader sub system)

  • .class에서 바이트코드를 읽고 메모리에 저장해줌
  • Loading(로딩): 자바 바이트 코드(.class)를 읽고 메소드 영역에 저장
  • Linking(링크): 클래스의 static 변수 등 필요로 하는 메모리를 할당
  • Initialization(초기화): static 값들을 초기화하고 변수에 할당함.

    클래스에는 static 값을 설정할 수 있고 이것을 다른 메서드에서 참조해서 사용할 수 있다. 이런 값들을 초기화하는 과정이라고 할 수 있다.

메모리(Runtime data areas)

  • 메소드 영역: 클래스 수준의 정보를 저장한다. (클래스 이름, 풀패키지 경로, 부모 클래스 이름, 메소드, 변수들)
  • 힙: 객체를 저장

    힙과 메소드는 공유 자원이지만, 스택, PC, 네이티브 메소드 스택은 쓰레드에 국한되는 자원이다.

  • 스택: 스택 영역에는 스레드마다 런타임 스택을 만들고 그 안에 메소드 호출을 스택 프레임이라 부르는 블럭으로 쌓는다. 쓰레드 종료를 하면 런타임 스택도 사라진다.

    예를들어 에러 메세지 로그를 보면 메소드가 쭉 쌓여있는 것을 볼 수 있다. 스택 안에 쭉 메서드 호출이 쌓여있는 것이다.

  • PC(Program Counter) 레지스터: 쓰레드 마다 쓰레드 내 현재 실행할 스택 프레임을 가리키는 포인터가 생성.
  • 네이티브 메소드 스택: 네이티브 메소드를 호출할 때 사용하는 별도의 메소드 스택. 네이티브 메소드는 네이티브 키워드를 붙여놓고 구현은 C나 C++로 구현된 메소드.

실행 엔진(Execution Engine)

  • 인터프리터: 바이트 코드를 한줄씩 실행한다. 한줄마다 네이티브 코드로 컴파일하는 것이다.
  • JIT 컴파일러: 인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면 JIT컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꾸고 인터프리터가 해당하는 라인을 보면 바로 네이티브 코드로 컴파일된 코드를 사용한다.
  • GC(Garbage Collector): 더이상 참조되지 않는 객체를 모아서 정리해줌

번외

JRE?

JRE는 자바 애플리케이션을 실행하는 데 필요한 모든 라이브러리와 실행 환경을 제공한다. 따라서 바이트 코드가 컴파일된 후, 이를 실행하기 위해서는 JRE가 필요하다. JRE는 JVM과 함께 설치되며, JVM은 JRE의 일부로서 바이트 코드를 실행할 수 있는 환경을 제공한다.

이 과정으로 인해 바이트 코드는 특정 운영 체제나 하드웨어에 종속되지 않고 독립적으로 존재할 수 있다.

다만, JVM은 실행하는 환경(OS)에 맞는 적절한 버전을 선택해서 프로그램을 실행해야만 한다.

JVM 기반 언어


스프링 부트 프로젝트를 만들 때 Java말고도 Groovy나 Kotlin을 선택하는 부분을 본적이 있을것이다. 이들은 모두 자바와 높은 호환성을 보이기 때문이다.

JVM은 자바뿐만 아니라 여러 다른 언어들도 지원한다. 예를 들어, 코틀린(Kotlin), 스칼라(Scala), 클로저(Clojure), 그루비(Groovy) 등의 언어는 자바와 높은 호환성을 가지고있으며 JVM 위에서 실행될 수 있다 = JVM을 런타임으로 사용하여 실행될 수 있다.

그럼 JVM 기반 언어를 컴파일해서 사용할 수 없을까?

JVM 계열 언어는 주로 바이트 코드로 컴파일되어 JVM에서 실행된다. 하지만 특정 언어나 프로젝트에 따라 AOT(Ahead-Of-Time) 컴파일러를 사용하여 네이티브 코드(<->Managed Code)로 컴파일할 수도 있다. 이걸로 JVM 없이도 프로그램을 실행할 수 있도록 한다.

AOT?


c/c++처럼 실행 전에 컴파일하는 방식이다.
자바의 컴파일 방식이 궁금하면?

GraalVM

  • 오라클에서 제공하는 GraalVM은 자바 애플리케이션을 네이티브 코드로 컴파일할 수 있다.
  • 예를 들어, Kotlin으로 작성된 애플리케이션을 GraalVM을 사용하여 네이티브 이미지로 컴파일하면, 해당 애플리케이션은 JVM 없이도 직접 실행할 수 있다
  • 기존 HotSpot JVM에서 C2를 Java기반으로 작성하여 변경

왜씀?

  • 말한대로 JVM언어로 작성된 어플리케이션을 직접 실행하기위함
  • 매우 빠르게 시작되고 즉각적임
  • 실행비용이 저렴함

다만 오해하지말아야하는건 JIT 컴파일러에 비해 성능이 좋다 라는게 아니다. 첫 실행속도가 빠른것이다. 그래서 JIT을 앞서기위해서는 개발이 더 필요하다고 함

JVM과 내부에서 실행되고 있는 프로그램은 부모 - 자식 프로세스 관계다?

JVM이 운영체제의 프로세스라면, Java 프로그램 내의 작업 단위는 스레드다. 스레드들은 JVM 프로세스 내에서 실행되며, 서로 메모리를 공유한다.

즉, 자바 프로그램을 실행하면 JVM 프로세스가 실행되고, JVM 프로세스 안에서 GC 를 포함한 여러 개의 스레드가 실행된다.


출처


profile
후회하지 않는 사람이 되자 🔥
post-custom-banner

0개의 댓글