본문 바로가기
JAVA/[JAVA] 바구니

[JAVA] Java Virtual Machine

by oncerun 2020. 7. 8.
반응형

JVM

 

- 자바는 WORA("한번 작성해 어디에서나 실행한다")의 원칙을 기반으로 한 언어이다. 1995년 자바가 나오기 이전의 모든 컴퓨터 프로그램은 특정 운영체제에 종속되어 설계되어 있었으며 프로그램 메모리는 전부 개발자가 관리했었어야 했다. 

 

- JVM은 자바 프로그램이 다양한 운영체제와 다양한 기기에서도 실행될 수 있게 하는 Virtual Machine이다 Machine이라고 표현하지만 사실은 소프트웨어이다.

컴파일된 바이너리 코드는 플랫폼에 종속받지 않고 실행시키는 것뿐만 아니라 프로그램 메모리를 관리하고 최적화까지 해주는 소프트웨어이다.

 

-JVM은 스택 기반 가상 머신이다. 가상 머신은 레지스터 기반과 스택 기반이 존재하는데 둘의 차이는 피연산자를 저장하고 다시 호출하는 메커니즘이 다르다. 스택은 피연산자와 연산 후 결과를 스택에 저장하며

스택 구조라서 PUSH & POP을 사용하며

레지스터 기반은 각 피연산자들의 주소를 개별적으로 기억하기 때문에 메모리에 할당되며 대신 명령어를 직접적으로 접근할 수 있기에 속도가 빠르며 명령어 최적화를 할 수 있다.

 

자바 애플리케이션을 실행하기 위해 JVM은 자바 클래스 로더(Class Loader)와 자바 실행 엔진(Execution Engine)과 Runtime Data Areas(할당받은 메모리 공간)에 의존한다.

 

 

 

 

 

 

Loding -> Linking -> initalization

 

 

 

 

클래스 로더란?

 

우리가 만든 클래스들을 JVM으로 동적으로 로드하는 JRE의 일부입니다.

바이너리 코드를 읽어와 메모리에 적절히 배치하는 역할을 합니다.

 

JVM이 시작되면 3개의 클래스 로더들이 사용된다

  1. 부트스트랩 클래스 로더

  2. 확장 클래스 로더

  3. 시스템 클래스 로더

부트스트랩 클래스 로더는 <JAVA_HOME>/jre/lib 디렉터리에 위치한 핵심 자바 라이브러리들을 불러들인다.

핵심 JVM의 일부분인 이 클래스 로더는 네이티브 코드로 작성되어 있다.

 

확장 클래스 로더는 확장 디렉터리(<JAVA_HOME>/jre/lib/ext 또는 java.ext.dirs 시스템 속성에 지정된 기타 디렉터리)에 코드를 로드한다. sun.misc.Launcher$ExtClassLoader 클래스에 의해 구현되어 있다.

 

java.class.path에서 볼 수 있는 시스템 클래스 로더는 CLASSPATH 환경 변수에 매핑된다. sun.misc.Launcher$AppClassLoader 클래스에 의해 구현되어 있다.

 

JVM은 클래스 로더 덕분에 파일의 구조나 파일 시스템을 고려하지 않을 수 있으면서 자바 프로그램을 작동시킬 수 있다.

자바 클래스들은 한 번에 모든 클래스가 메모리에 올라가지 않는다. 각 클래스들은 필요할 때 애플리케이션에 올라가게 되며, 이 작업을 클래스 로더가 해주게 된다.

 

 

1. java 컴파일러가 java 코드를 해석한 뒤. class파일 형태로 결과를 생성한다.

이 코드는 byte코드이다.

 

 

2. 클래스 로더에 의해. class 파일들은 다음 단계를 거친다.

 

(1) Loading : 클래스 파일에서 패키지 경로 , 클래스의 상속 정보 , 변수 , 생성자 등등 클래스의 관한 정보를 로딩해서 바이너리 데이터로 변경. 그런 뒤 메서드 영역에 저장한다.

Bootstrap , Extension , Application 순으로 앞의 loader가 로딩할 수 없다면 그다음 Loader가 읽어낸다.

 

(2) Linking : 바이트 코드를 검증하고 필요한 만큼 메모리를 할당한다.

Verify :. class 파일 형식이 유효한지 검사한다. 

Prepare : static 변수와 기본 값에 필요한 메모리를 준비한다.

Resolve : 심볼릭 메모리 레퍼런스를 실제 메모리 레퍼런스로 교체한다. 다만 교체될 수도 있으며 사용이 일어날 때 동적으로 교체될 수도 있다.

 

-Symbolic Reference : 실제 메모리 주소 값이 아닌, 참조하는 대상의 이름으로만 지칭하고 있는 것이다. 

 

(3) Initialization : static block의 초기화 및 static 데이터들을 할당한다.

 

 

Execution engine

-클래스 로더가 런타임 데이터 영역에 바이트 코드를 배치시키면 실행 엔진에 의해 실행된다.

 

바이트 코드는 네이티브 코드가 아니기 때문에 실행 엔진은 네이티브 코드로 변환하는데 2가지 방식이 존재한다.

(1) Interperter

- 인터프리터는 바이트 코드를 Line by Line으로 해석하고 실행시킨다.

한 줄식 해석하기 때문에 속도면에서 느린 편이다.

 

(2) JIT

-인터프리터의 단점을 보안하기 위한 컴파일러, 인터프리터 방식으로 동작하다가 적절한 시점에 바이트 코드를 전체 컴파일하여 네이티브 코드로 변경하며, 그 이후에는 네이티브 코드를 직접 실행하는 방식입니다.

변환 덴 네이티브 코드는 캐시에 보관하기 때문에 한번 컴파일된 코드는 빠르게 수행됩니다. 하지만 컴파일하는 과정이 추가되었기 때문에 인터프리팅하는 것보다 오랜 시간이 소요됩니다.

 

 

(3) Garbage Collector

- Un-referenced Object 들을 제거해주는 가비지 컬렉팅을 수행한다.


 

 

 

Runtime Data Areas

 

메모리는 다음과 같이 나눌 수 있다.

(heap , method Area)는 전체 공유자원으로 분류하며, (JVM stack, PC, Native Method stack)는 스레드 단위의 자원으로 분류됩니다.

 

Method area : JVM 메서드 영역은 메타데이터, 상수, runtime pool 및 메서드 코드와 같은 클래스 구조를 저장합니다.

 

Heap : 모든 객체, 관련 인스턴스 변수 및 배열은 힙에 저장됩니다. 이 메모리는 여러 스레드에서 공유됩니다.

 

Natice method stack :  java가 아닌 다른 언어로 작성된 코드를 위한 공간이다. 기계어로 작성된 프로그램을 실행시키는 영역이다.

 

JVM 스택 영역 : 지역 변수를 임시 저장하며 부분적인 결과(호출된 메서드의 리턴 값, 연산 시 발생되는 값)입니다. 메서드가 호출 시마다 새 프레임이 작성되고 메서드 호출 프로세스가 완료되면 삭제됩니다.

 

PC Register : 현재 실행할 부분의 가상 머신 명령어의 주소를 저장하며 각 스레드마다 별도의 PC가 존재합니다.

Thread가 어떠한 부분을 어떤 명령으로 실행해야 할 지에 대한 기록을 하는 부분입니다.

 

Java가 느린 주요 이유는

1. 동적 Linking : c와 달리 링크는 런타임 시 프로그램이 java로 실행될 때마다 바이트코드를 검증하고 메모리를 할당하기때문입니다

2. 런타임 인터프리터 : 바이트 코드를 네이티브 코드로 변환하면서 런타임 시 java에서 수행됩니다

 

-최신 버전 java는 성능 병목 현상을 상당 부분 해결했습니다.

반응형

'JAVA > [JAVA] 바구니' 카테고리의 다른 글

[JAVA] 예외 처리  (0) 2021.03.27
Java의 기본 log : Logger  (0) 2021.02.26
[JAVA] RuntimeException  (0) 2020.06.06
[JAVA] Exception  (0) 2020.06.06
[JAVA] Wrapper Class  (0) 2020.05.25

댓글