본문 바로가기
Java 웹 프로그래밍

JVM 구조

by irerin07 2019. 6. 14.
728x90

 

자바 코드의 수행 과정

Class Loader가 컴파일 된 자바 바이트 코드를 런타임 데이터 영역에 로드하고, 실행 엔진이 자바 바이트 코드를 실행한다.

 

Class Loader

자바는 런타임에 클래스를 처음 참조 시 해당 클래스를 로드하고 링크한다. – 동적 로드

이 동적 로드를 담당하는 부분이 JVM Class Loader

-       특징

 n  계층구조 - Class Loader끼리 부모-자식 관계를 이루고 있다.

    u  최상위 Class LoaderBootstrap Class Loader라고 한다.

 n  위임 모델 계층 구조를 바탕으로 Class Loader끼리 로드를 위임하는 구조

    u  클래스를 읽어올 때 먼저 상위 Class Loader를 확인, 없다면 로드를 요청 받은 Class Loader가 클래스를 로드 한다.

 n  가시성 상위 Class Loader는 하위 Class Loader의 클래스를 찾을 수 없지만 하위 Class Loader는 상위 Class Loader의 클래스를 찾을 수 있다.

 n  언로드 불가 - Class Loader는 클래스를 로드 할 수는 있지만 언로드는 불가능하다.

    u  대신 현재 Class Loader를 삭제하고 새로운 Class Loader생성하는 방식으로 대신한다.

-       Class Loader는 로드된 클래스들을 보관하는 Namespace를 갖는다. 이미 로드된 클래스인지 여부를 확인하기 위해 namespace에 보관된 Fully Qualified Class Name을 기준으로 클래스를 찾는다.

 n  FQCN이 갖지만 namespace가 다르다면, 다른 Class Loader가 로드 한 클래스이므로 다른 클래스로 간주한다.

-       Class Loader가 클래스 로드를 요청 받으면

 n  Class Loader캐시에서 이전에 로드된 클래스인지 확인

 n  없다면 상위 Class Loader를 거슬러 올라가며 확인

 n  최상위 Class LoaderBootstrap Class Loader까지 확인해서 없다면 요청받은 클래스 로더가 파일 시스템에서 해당 클래스를 찾는다.

-       Bootstrap Class Loader

 n  Object클래스 혹은 기본 Java API등을 로드한다.

-       Extension Class Loader

 n  기본 Java API등을 제외한 확장 클래스들을 로드한다.

-       System Class Loader

 n  사용자가 지정한 $CLASSPATH내의 클래스들을 로드한다.

-       User Defined Class Loader

 n  사용자가 직접 코드 상에서 생성해 사용하는 Class Loader

Class Loader가 아직 로드되지 않은 클래스를 찾으면 다음과 같은 과정을 거쳐 클래스를 로드하고 링크한뒤 초기화 한다.

 

 

 

Loading – 클래스를 파일에서 가져와 JVM의 메모리에 업로드 한다.

Verifying – 읽어 들인 클래스가 자바 언어 명세(Java Language Specification) JVM명세에 명시된 대로 잘 구성되어 있는지 검사한다.

Preparing – 클래스가 필요로 하는 메모리를 할당, 클래스에서 정의된 필드, 메서드, 인터페이스들을 나타내는 데이터 구조를 준비한다.

Resolving – 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다.

-       심볼릭 레퍼런스 기본 자료형을 제외한 모든 타입을 명시적인 메모리 주소가 기반의 레퍼런스가 아닌 심볼릭 레퍼런스를 통해 참조한다.

-       실제 객체를 가져오기 위하여 사용되는 문자열

-       Person p = new Person();

Initializing – 클래스 변수들을 적절한 값으로 초기화. Static Initializer들을 수행하고 static 필드들을 설정된 값으로 초기화 한다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

런타임 데이터 영역

 

런타임 데이터 영역은 JVM이라는 프로그램이 운영체제 위에서 실행되며 할당 받는 메모리 영역

Pc Register, JVM Stack, Native Method Stack은 스레드 마다 하나씩 생성되고 Heap, Method Area, 런타임 상수 풀은 모든 스레드가 공유해서 사용한다.

-       PC Register (Program Counter Register)

 n  스레드가 시작될 때 생성된다. 현재 수행중인 JVM명령의 주소를 가지고 있다.

-       JVM스택

 n  스레드가 시작될 때 생성된다.

 n  Stack Frame이라는 구조체를 저장하는 스택

 n  JVM은 오직 JVM스택에 Stack Frame을 추가(Push)하고 제거(Pop)하는 동작만 수행

 n  Stack Trace의 각 라인은 하나의 스택 프레임을 표현한다.

-       Stack Frame

 n  JVM내에서 메서드가 수행될 때마다 하나의 스택 프레임이 생성되고 해당 스레드의 JVM 스택에 추가된다. 메서드가 종료시 스택 프레임이 제거된다.

   u  Local Variable Array – 지역변수 배열

     l  0부터 시작하는 인덱스를 가진 배열

     l  0은 메서드가 속한 클래스 인스턴스의 this레퍼런스

     l  1부터는 메서드에 전달된 파라미터들이 저장된다.

     l  그 이후로는 메서드의 지역 변수들이 저장된다.

   u  Operand Stack – 피연산자 스택

     l  메서드의 실제 작업 공간

     l  각 메서드는 피연산자 스택과 지역 변수 배열 사이에서 데이터를 교환하고 다른 메서드 호출 결과를 추가하거나(Push) 꺼낸다(Pop).

   u  Reference to Constant Pool – 현재 실행 중인 메서드가 속한 클래스의 런타임 상수 풀에 대한 레퍼런스

   u  이 셋의 크기는 컴파일 시에 결정된다. 그렇기 때문에 스택 프레임의 크기도 메서드에 따라 크기가 고정된다.

-       Native Method Stack

 n  자바 이외의 언어로 작성된 네이티브 코드를 위한 스택

-       메서드 영역

 n  모든 스레드가 공유하는 영역

 n  JVM이 시작될 때 생성된다.

 n  JVM이 읽어 들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메서드 정보, static변수, 메서드의 바이트코드 등을 보관

 n  흔히 PermGen이라 불린다(자바 8 이전)

-       런타임 상수 풀

 n  각 클래스와 인터페이스의 상수 뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블

 n  어떤 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리 상 주소를 찾아서 참조한다.

-       Heap

 n  인스턴스 또는 객체를 저장하는 공간으로 Garbage Collection대상이다.

 

실행 엔진(Execution Engine)

Class Loader를 통해 JVM의 런타임 데이터 영역에 배치된 바이트 코드는 실행 엔진에 의해 실행.

실행 엔진은 바이트 코드를 명령어 단위로 읽어서 실행한다.

자바 바이크 코드는 기계가 바로 수행할 수 있는 언어는 아니다.

그래서 JVM내부에서 기계가 실행할 수 있는 형태로 변경한다

-       인터프리터 방식: 바이트코드 명령어를 하나씩 읽어서 해석하고 실행

-       JIT compiler: 인터프리터 방식으로 실행하다 어느 시점에 바이트 코드 전체를 컴파일하여 네이티브 코드로 변경. 이후에 해당 메서드를 더 이상 인터프리팅 하지 않고 네이티브 코드로 직접 실행하는 방식. 네이티브 코드를 캐시에 보관되기 때문에 한 번 컴파일 된 코드는 계속 빠르게 수행가능하다. 다만 바이트 코드를 하나씩 인퍼프리팅 하는 것보다 훨씬 오래 걸린다.

 

 참고 및 출저 : https://d2.naver.com/helloworld/1230

728x90