☕️ Java/기본

자바는 어떻게 작동하는가? (JVM, Class Loader, JVM Memory 등)

말 랑 2022. 1. 24. 20:45
728x90

 

 

 

 

 

 

자바 프로그램의 실행 과정

 

 

자바 컴파일러 (Java compiler)

자바 컴파일러는 자바를 가지고 작성한 자바 코드를 자바 가상머신(JVM)이 이해할 수 있는 자바 바이트코드로 변환하는 역할을 수행한다. '.java' 파일을 '.class' 파일로 변환하는 것이다.

자바 컴파일러는 자바를 설치하면 javac.exe 라는 실행 파일의 형태로 설치된다.

 

 

 

 


 

자바 바이트코드

 

바이트코드란?

특정 하드웨어가 아닌 가상 컴퓨터에서 작동하는 실행 프로그램을 위한 이진 표현법.

 

 

 

자바 바이트코드란 자바 가상 머신(JVM)이 이해할 수 있는 언어로 변환된 자바 소스 코드를 의미한다.

자바 바이트코드의 확장자는 .class 이며, 자바 바이트 코드는 자바 가상 머신(JVM)이 설치되어 있다면 어떠한 운영체제에서도 실행될 수 있다.

 

 


 

 

JVM

JVM(Java Virtual Machine)은 Java 응용 프로그램을 실행하는 런타임 엔진 역할을 한다.

자바 코드에 존재하는 메인 메소드를 호출하는 것이 바로 이 JVM이다.

JVM은 JRE(Java Runtime Environment)의 일부이다.

 

자바는 운영체제에 독립적(또는 WORA[Write Once Run Anywhere]라고도 함)이라고 하는데, 이것이 가능한 이유가 모두 JVM 덕분이다.

 

우리가 .java 파일을 컴파일할 때 .java파일에 존재하는 클래스 이름을 가진 .class 파일(자바 바이트코드)이 Java 컴파일러에 의해 생성되며, JVM이 .class 파일(자바 바이트코드)을 해석하고 실행한다.

 

 

 

Java의 작동 흐름

 

 

 

 


 

Class Loader

 

클래스 로더의 하위 시스템

Loading(로딩), Linking(연결), Initialization(초기화)

 

주로 위 3가지 역할을 담당한다.

 

 

 

 

Loading

클래스 로더는 .class 파일을 읽고, 해당 파일에 대응하는 바이너리 데이터를 생성한 뒤 Method Area에 저장한다.

각각의 .class 파일에 대해 JVM는 메소드 영역에 다음 정보를 저장한다

  • 로드된 클래스와 그의 부모(parent) 클래스의 정규화된 이름(The fully qualified name라 나와있는데 해석이..ㅠ)
  • .class 파일이 Class, Interface, Enum과 관련이 있는지에 대한 여부
  • 수정자, 변수 및 메서드 정보 등

 

.class 파일의 로딩이 끝난 후, JVM은 해당 .class 파일을 heap memory에 나타내기 위해 Class 타입의 객체를 생성한다.

해당 객체는 java.lang 패키지에 미리 정의된 Class 타입이라는 것을 주목하자.

이러한 Class 타입의 객체는 개발자가 클래스 수준의 정보(예를 들어 클래스의 이름, 부모 클래스의 이름, 메서드들과 변수들의 정보 등)를 얻어오는 데 사용될 수 있다.

우리는 해당 객체의 getClass() 메서드를 통해 객체 클래스의 정보를 얻을 수 있다.

 

 

 

Linking

검증(verification), 준비(preparation) 및 해결(resolution)을 수행한다.

 

 

  • Verification: .class 파일의 정확성을 보장한다. 즉, 이 파일이 올바른 형식으로 지정되고 유효한 컴파일러에서 생성되었는지 여부를 확인한다. 확인에 실패하면 런타임 예외 java.lang.VerifyError가 발생한다. 이 활동은 ByteCodeVerifier 에 의해 수행되며, 이 활동이 완료되면 클래스 파일을 컴파일할 준비가 된 것이다.
  • Preparation: JVM은 클래스 변수에 메모리를 할당하고 메모리를 기본값으로 초기화한다.
  • Resolution:  It is the process of replacing symbolic references from the type with direct references. It is done by searching into the method area to locate the referenced entity
    • (번역이 조금 이상해서.. 아마 다음 뜻인것 같습니다) 인터페이스 참조를 실제 구현 클래스 참조로 바꾸는 과정이다. 참조된 엔터티를 찾기 위해 Method Area를 검색하여 수행됩니다.

 

 

 

Initialization

이 단계에서 모든 static 변수는 코드 및 static 블록(있는 경우)에 정의된 값으로 할당된다.

이것은 클래스에서는 위에서 아래로, 클래스 계층에서는 부모에서 자식으로 실행된다.

 

 

 

 

 

클래스 로더의 종류

일반적으로 3가지 클래스 로더가 있다.

 

  • Bootstrap class loader : 구현된 모든 JVM은 반드시 bootstrap class loader를 가지고 있어야 하며, 이는 신뢰할 수 있는 클래스를 로드할 수 있다. Bootstrap class loader는 "JAVA_HOME/jre/lib" 디렉토리에 있는 핵심 자바 API 클래스를 로드한다. 이 경로는 일반적으로 부트스트랩 경로로 알려져 있다. C, C++과 같은 네이티브 언어로 구현된다.
  • Extension class loader : Bootstrap class loader의 자식이다. 확장 디렉토리 "JAVA_HOME/jre/lib/ext"(확장 경로) 또는 java.ext.dirs 시스템 속성에 의해 지정된 기타 디렉토리에 있는 클래스를 로드한다. Java에서 sun.misc.Launcher$ExtClassLoader 클래스에 의해 구현된다.
  • System/Application class loader : Extension class loader의 자식이다. 애플리케이션 클래스 경로에서 클래스를 로드하는 역할을 한다. 내부적으로 java.class.path에 매핑된 환경 변수를 사용한다. 또한 sun.misc.Launcher$AppClassLoader 클래스에 의해 구현된다.

 

// Java code to demonstrate Class Loader subsystem
public class Test {
    public static void main(String[] args)
    {
        // String class is loaded by bootstrap loader, and
        // bootstrap loader is not Java object, hence null
        System.out.println(String.class.getClassLoader());
  
        // Test class is loaded by Application loader
        System.out.println(Test.class.getClassLoader());
    }
}

 

Output

null
jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f

 

 

JVM은 Delegation-Hierarchy 원칙에 따라 클래스를 로드한다.

시스템 클래스 로더는 확장 클래스 로더에 로드 요청을 위임하고, 확장 클래스 로더는 부트스트랩 클래스 로더에 요청을 위임한다. 부트스트랩 경로에서 클래스가 발견되면 해당 클래스가 로드되고 그렇지 않으면 요청이 확장 클래스 로더로 다시 전송된 다음 시스템 클래스 로더로 전송된다. 마지막으로 시스템 클래스 로더가 클래스를 로드하는 데 실패하면 런타임 예외 java.lang.ClassNotFoundException이 발생한다.

 

클래스 로드 과정

 

 

 

 

 


 

JVM Memory 영역을 알아보기 전에 PermGen과 Metaspace 영역에 대해 알아야 할 필요성이 있다.

 

PermGen Vs Metaspace

 

PermGen (permanent generatio)

Java 7 이하의 버전에서 존재한 영역으로, 클래스의 메타 데이터가 들어가는 공간이다.

또한 모든 static object가 이곳에 저장되었으며, 바이트 코드, JIT 정보에 대한 데이터, String Constant Pool도 이곳에 포함되었다.

PermGen은 메모리 영역의 크기가 고정되어 있으며 OutOfMemoryError를 발생시키는 원인이기도 하다.

 

 

 

Metaspace

Java 8 버전부터 새로 등장한 메모리 공간으로, PermGen 영역을 대체하는 공간이다.

Metaspace는 native memory(OS에서 애플리케이션에 제공하는 메모리)를 사용한다.

(static은 Java 7 이전에는 PermGen에 저장되었으나, Java 8 이후부터는 PermGen의 대체 공간인 Metaspace가 아닌, Heap 영역에 저장된다. 추가로 String Constant Pool도 Heap으로 옮겨졌다.)

(즉 클래스의 멤버변수(클래스변수와 인스턴스변수)는 Java 8 이후로 모두 Heap 영역에 저장된다.)

 

 

 

 


 

JVM Memory

 

 

 

Runtime Data Area

JVM이 프로그램을 수행하기 위해서 OS로부터 할당받는 메모리의 영역이다. 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재한다.

 

이 영역은 크게 Method Area, Heap Area, Strack Area, PC Register, Native Method Stack으로 나눌 수 있다.

 

노란색 글씨들인 우측 3개의 영역은 각 Thread 별로 생성이 되고, 좌측 2개의 영역은 모든 Thread가 공유한다.

 

 


 

Method area 

모든 Thread가 공유한다.

 

Method area 영역에서는, 모든 클래스 수준의 정보(메타 데이터 - 클래스 이름, 부모 클래스 이름, 메서드들과 변수들 [멤버변수는 이제 모두 Heap 영역에 올라가므로 Method area에는 저장되지 않는다]등)가 저장된다.

(static이 Method area에 저장된다는 글이 있는데, 이는 Java 8 이전의 이야기이며, Java 8 이후부터는 Heap 영역에 저장된다.)

JVM 하나당 하나의 Method area를 가지며, 이곳의 자원들은 공유될 수 있다.

metaspace 영역에 속한다.(자바 8 이전에는 PermGen[permanent generation]영역에 속했었다.)

 

 


 

Heap area

모든 Thread가 공유한다.

 

모든 생성된 객체의 정보는 힙 영역에 저장된다.

인스턴스와 배열이 동적으로 생성되는 공간이자 GC(가비지 컬렉터)의 대상이 되는 영역이다.

모든 쓰레드에서 공유하므로 동기화 문제가 발생할 수 있다.

(힙 영역은 다양한 영역으로 세분화되어 구성되는데, 아래 링크에서 자세히 설명한다)

https://ttl-blog.tistory.com/368

 

[Java] 자바 메모리 관리 파헤치기 (스택, 힙, Reference Type, 가비지 컬렉터)

시작하기에 앞서 자바에서 일반적으로 구성되는 메모리의 구조는 다음과 같습니다. 일반적으로 메모리는 크게 stack과 heap 두 파트로 나누어집니다. 이 둘에 대해서 자세히 알아보도록 하겠습니

ttl-blog.tistory.com

 

 


 

 

Stack area

Thread별로 1개씩 존재한다.

 

지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역입니다.

(heap 영역에 존재하는 객체들에 대한 참조와 primative type인 지역 변수들이 Stack area에 저장된다)

 

Thread의 Method를 호출할 때 위 수행 정보들이 Frame 이라는 단위로 JVM stack에 저장됩니다.

그리고 이렇게 스택 영역에 차례대로 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 한다.

 

Method 호출이 종료될 때 stack에서 제거됩니다.

 

 

 

 

참고. primitive type의 저장 위치

멤버변수(인스턴스변수, 클래스(static)변수)로 선언된 primitive type의 변수는 Heap에 저장되며, 지역변수(local variable) Stack에 저장된다.

 

 

 


 

PC Registers

Thread별로 1개씩 존재한다.

 

스레드의 현재 실행 명령의 주소를 저장한다. 각 스레드에는 별도의 PC 레지스터가 있다.

 

 


 

Native method stacks

Thread별로 1개씩 존재한다.

 

스레드 당 하나의 Native method stack을 가진다. Java외 다른 언어들로 작성된 Native method 정보를 저장한다.

 

 

 


 

 

Execution Engine

 

실행 엔진은 ".class"(바이트 코드)를 실행한다. 바이트 코드를 한 줄씩 읽고, 다양한 메모리 영역에 있는 데이터와 정보를 사용하고, 명령을 실행한다. 세 부분으로 분류할 수 있다.

인터프리터: 바이트코드를 한 줄씩 해석한 후 실행한다. 여기서 단점은 하나의 메소드를 여러 번 호출할 때 매번 해석이 필요하다는 것이다.


Just-In-Time Compiler(JIT) : 인터프리터의 효율성을 높이기 위해 사용한다. 전체 바이트 코드를 컴파일하여 네이티브 코드로 변경하여 인터프리터가 반복되는 메서드 호출을 볼 때마다 JIT에서 해당 부분에 대한 직접 네이티브 코드를 제공하므로 재해석이 필요하지 않아 효율성이 향상된다.

 


Garbage Collector: 참조되지 않은 객체를 파괴한다. (메모리의 회수)

 

 

 


 



Java Native Interface (JNI)

Native Method Libraries와 연동하여 실행에 필요한 Native Library(C, C++)를 제공하는 인터페이스이다.

JVM이 C/C++ 라이브러리를 호출하고 하드웨어에 특정한 C/C++ 라이브러리에서 호출할 수 있도록 한다.

 


 


Native Method Libraries

Execution Engine에서 필요로 하는 Native Libraries(C, C++)의 모음이다.

 

 

 


 

 

 

📔 Reference

 

https://www.geeksforgeeks.org/jvm-works-jvm-architecture/https://www.geeksforgeeks.org/jvm-works-jvm-architecture/

 

How JVM Works - JVM Architecture? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

https://inspirit941.tistory.com/294

 

JVM의 메모리 구조 및 할당과정

JVM 구조 JVM은 다섯 가지 컴포넌트로 구성되어 있다. 클래스 로더 시스템 : 컴파일 결과로 만들어진 .class 바이트코드 파일을 읽어들여 메모리에 배치. 로딩, 링크, 초기화 세 가지 과정을 거친다.

inspirit941.tistory.com

https://www.betsol.com/blog/java-memory-management-for-java-virtual-machine-jvm/

 

Java Memory Management for Java Virtual Machine (JVM) | Betsol

JVM (Java Virtual Machine): Java memory management is an ongoing challenge and a skill that must be mastered to have properly tuned applications that function in a scalable manner. Fundamentally, it is the process of allocating new objects and properly rem

www.betsol.com

https://stackoverflow.com/questions/50163218/is-method-area-still-present-in-java-8

 

Is Method area still present in Java 8?

Prior to Java 8 we had 5 major runtime data areas: Method Area Heap JVM Stacks PC registers Native method stacks With Java 8, there is no Perm Gen, that means there is no more “java.lang.

stackoverflow.com

https://jgrammer.tistory.com/144

 

[JAVA] Java8부터는 static이 heap영역에 저장된다?

static은 런타임시 클래스 로더에 의해 메서드 영역에 적재되며 프로그램이 종료될 때 까지 GC에 대상이 아니라고 알고있었다. 그런데, permanent영역과 metaspace에 관련된 글을 읽는 중 static이 heap영

jgrammer.tistory.com

https://1-7171771.tistory.com/140

 

JAVA8 이후의 heap 메모리 구조와 GC 알고리즘

1. Java8 이전까지의 Heap 메모리 구조 heap 메모리 영역은 크게 3개의 영역으로 분리되어 있다. 1. New/Young 일단 메모리에 객체가 생성되면 Eden 영역에 객체가 지정된다. Eden 영역에 데이터가 가득 차

1-7171771.tistory.com

https://openjdk.java.net/jeps/122

 

JEP 122: Remove the Permanent Generation

JEP 122: Remove the Permanent Generation OwnerJon MasamitsuTypeFeatureScopeImplementationStatusClosed / DeliveredRelease8Componenthotspot / gcDiscussionhostspot dash dev at openjdk dot java dot netEffortXLDurationXLBlocksJEP 156: G1 GC: Reduce need

openjdk.java.net

https://mia-dahae.tistory.com/101

 

JVM Runtime Data Area- Heap, Method Area

Method Area And Heap 1. Head Heap에는 Class Object,Instances 들이 저장 된다. Heap에 Object들을 저장한다는 것은 Instances들의 데이터를 저장한 다는 의미 이다. (Intances 변수들의 갯수, 타입 ) 2. Method..

mia-dahae.tistory.com

https://www.geeksforgeeks.org/metaspace-in-java-8-with-examples/

 

MetaSpace in Java 8 with Examples - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

http://www.tcpschool.com/java/java_intro_programming

 

코딩교육 티씨피스쿨

4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등

tcpschool.com

 

728x90