BackEnd/자바

JVM, JRE, JDK, 메모리

ssseung 2020. 12. 14. 21:34

 

일반 프로그램은 운영체제에서 바로 실행되는 반면, 자바 프로그램은 JVM 을 거쳐 실행된다.

 

JVM 이란 (Java Virtual Machine)

자바 가상 머신으로 자바 바이트 코드를 인터프리터와 JIT 컴파일러를 이용해 OS 에 특화된 코드로 변환한다.

 

바이트 코드를 실행하는 표준의 의미 JAVA SE

바이트 코드를 실행하는 표준을 구현한 구현체도 JVM이라는 용어를 사용한다.

Oracle, Azul, Amazon-corretto, AdoptOpenJDK 등 벤더에 따라 구현이 다르다.

 

바이트 코드

자바 컴파일을 하면 .class  파일이 나오고 .class 안에 있는 코드가 바이트 코드다.

이 바이트코드는 실제 실행될 때 다시 한번 기계가 읽을 수 있는 형태(native code)로 interpreter 를 통해 해석이 되어야 한다. 이렇게 한번에 기계어로 변환하지 않고 두번의 과정을 밟는 이유는 Java 의 최대 장점 중 하나인 machine-independent 특성때문이다.  

platform independent 라고도 하는데, 한번 작성하면 어떤 기계에서든 돌릴 수 있다는 특성을 말한다.

 

인터프리터와 JIT 컴파일러가 이 바이트 코드가 머신이 읽을 수 있는 코드로 변환한다.

 

인터프리터 

바이트 코드를 한줄씩 실행 

 

JIT 컴파일러

인터프리터의 효율을 높이기 위해 , 인터프리터가 반복되는 코드를 발견하면 JIT 컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꾼다. 그 다음부터는 네이티브 코드로 컴파일된 코드를 바로 사용한다. 


JRE은 JVM 최소한의 배포단위로 자바 애플리케이션 실행할 수 있도록 구성되어 있다.

JVM과 library가 함께 있다.

JRE 만 있어도 실행은 할 수 있지만 컴파일러 javac 는 JVM 에 있다.

jlink 같은걸 이용해 JRE 를 직접 만들 수도 있다.

 

JDK는  JRE에 개발에 필요한 툴까지 함께 구성되어있다.

JDK는 javap - c  컴파일 툴까지 제공 

자바 11부터 JRE 를 제공하지 않는다.  

 

 

 

JVM 역할


JVM 내부 영역별 역할

 

클래스 로더 (Class Loader) 

JVM 내로 클래스를 로드하고 링크를 통해 배치하는 작업을 수행하는 모듈로 ,

런타임시 동적으로 클래스를 로드한다.

프로그램 실행 시에, 컴파일러에 의해 변환 된 Byte Code(.Class)를 읽어 메모리에 저장하는 역할을 합니다.

 

실행 엔진 (Excution Engine) 

Class Loader에 의해 JVM 메모리 공간에 저장 된 Byte Code를 하나의 명령어 단위로 읽어 들여 실행하도록 합니다.

 

Garbage Collector (GC)

사용하지 않는 객체들을 메모리에서 해제하는 역할을 합니다

 

RunTime Data Area

JVM이 프로그램을 수행하기 위 해 운영체제로부터 할당받은 메모리 공간입니다.

 

  • 작성된 소스코드(.java)는 컴파일러(javac.exe)를 통해 JVM이 읽을 수 있도록 Byte Code(.Class)파일로 변환됩니다. 이렇게 변환 된 Byte Code파일을 JVM 내부의 Class Loader가 읽어들여 Runtime Data Area(Memory Area)에 저장하게 됩니다. 저장된 코드들을 Excution Engine이 하나의 명령어 단위로 읽어들여 프로그램을 실행하게됩니다.  그리고 사용이 끝나 더 이상 사용하지 않는 코드들을 Gabage Collector가 모아서 메모리에서 해제합니다.

JVM  내부 메모리 구조


클래스 로더 내부

 

로딩 : 클래스를 읽어오는 과정

 - 클래스 로더가 .class 를 읽고 그 내용에 따라 적절한 바이너리데이터를 만들고 메서드 영역 에 저장.

 - FQCN (Fully Qualified Class Name), 클래스, 인터페이스, 이늄,  메서드, 변수 로딩이 끝나면

   해당 클래스 타입의  Class 객체를 생성해 힙 영역 에 저장

 

> 부트 스트랩 클래스 로더 : JAVA_HOME\lib 에 있는 코어 자바 API 제공 . 최상위 우선순위.

> 플랫폼 클래스 로더(익스텐션 클래스 로더) : JAVA_HOME\lib\ext 폴더나 java.ext.dirs 시스템변수에 해당하는 위치에 있는 클래스

> 애플리케이션 클래스 로더 : 애플리케이션 클래스 패스 (java.class.path 환경변수 값이나 애플리케이션 실행할 때 주는 classpath옵션)에서 클래스를 읽는다.

 

public class App {

	public static void main(String[] args) {
		ClassLoader classLoader = App.class.getClassLoader();
		System.out.println(classLoader);
		System.out.println(classLoader.getParent());
		System.out.println(classLoader.getParent().getParent());
	}

}

jdk.internal.loader.ClassLoaders$AppClassLoader@6aaa5eb0
jdk.internal.loader.ClassLoaders$PlatformClassLoader@2c9f9fb0
null //네이티브 코드로 구현되어 있어 부트스트랩 클래스 로더는 읽을 수 없다.

 

링크 : 레퍼런스를 연결하는 과정

> 검증 : .class 파일이 유효한지 체크

> preparation : 클래스변수(static)와 기본값에 필요한 메모리

> resolve (optional) :  심볼릭 레퍼런스를 메서드 영역에 있는 실제 레퍼런스로 교체

 

초기화 : static 값들 초기화 및 변수에 할당 

 


RunTime Data Area 내부 영역별 역할

 

JVM 구조 

 

힙 영역( Heap Area) : 다른 모든 영역에서 접근 가능

new 키워드, 인스턴스, 배열 등 생성된 객체에 대한 메모리를 동적으로 할당.

애플리케이션 영역에 접근할 수 있는 메모리의 메인영역이다.

Thread 에서 공유하는 영역이다.

참조하는 변수나 필드가 없다면 GC의 대상의 된다.

*객체를 할당할 때 이용할 수 있는 메모리가 충분하지 않으면 JVM은 카비지 컬렉션을 이용해 힙에서 메모리를 재사용하려고 한다. 그래도 충분한 메모리 영역을 확보할 수 없다면 OutOfMemory 에러가 발생한다.

 

 

메서드 영역 (Method Area) -- 다른 모든 영역에서 접근 가능

클래스 정보를 처음 메모리로 올릴 때 초기화 되는 대상을 저장하기 위한 메모리 공간

클래스와 인터페이스에 대한 런타임 상수 풀, 멤버변수,클래스변수,메서드,클래스 수중의 정보 풀 패키지 정보 등 저장. 

 

*상수 풀 : 클래스와 같은 heap 의 permanent area에 생성되어 java 프로세스 종료까지 그 생을 함께 한다.

String 을 new 로 생성하지 않고 " " 리터럴을 사용하여 생성할 경우, 내부적으로 new String 을 생성한 뒤에 String.intern()이라는 메서드가 호출되어 고유의 인스턴스를 공유하도록 interned 된다. 이것은 생성한 String 을 constant pool 에 등록하는 작업을 한다. (만약 이전에 같은 char sequence 의 문자열이 이미 상수풀에 있다면 문자열을 heap 에서 해제하고 그 상수풀의 레퍼런스를 반환)

즉. 같은 패키지 내의 같은 클래스 내에서는 정수 스트링들은 동일한 String 객체를 참조한다.

 

System.out.println("String address test");

String newTest1 = new String("a");
String test1 = "a";

System.out.println(newTest1==test1); //false

String test2 = "a";

System.out.println(test1==test2); //true
        
newTest1 = test1;
System.out.println(newTest1==test1); //true

 

 

스택 영역 (Stack Area): 스레드 영역에서 공유 되는 자원 

지역변수, 매개변수(메서드 내에서 유효 / 로컬변수) , 객체의 참조, 메서드를 저장한다.

메서드 실행이 끝나면 소멸된다. 재귀 메서드를 호출하면 StackOverFlow 에서가 발생할 수 있다.

각 Thread 마다 하나씩 존재한다.

*스레드마다  runtime 스택이란걸 만들고 그 안에 stack frame 을 쌓는다. stack frame  = method call 

쌓인 스택에서 현재 어느 위치를 실행하고 있는지 PC Register 가 기록한다.

 

스택 : 객체의 참조

 

PC Register : 스레드 영역에서 공유 되는 자원

Thread가 시작될 때 생성되며 Thread 마다 존재한다.

Thread 가 어떤 부분을 어떤 명령어로 실행해야 할 지에 대한 기록을 한다.

PC Register는 현재 실행되고 있는 부분의 주소(Adress)를 가지고 있다.

현재 실행되고 있는 명령이 종료되면 카운트 값을 증가시켜 다음 명령을 실행하게 한다.

 

Native Method Area : 스레드 영역에서 공유 되는 자원 

자바 외 언어(C, C++ 등)을 수행하기 위한 Stack 영역.

프로그램 실행 도중 호출 된 메서드가 Native 방식을 사용하는 메소드 일 경우, 이 영역에 저장되어 처리된다.

 

 

 

 

반응형