Post
KO

JVM은 도대체 어떻게 구동될까? GC 포함

JVM 시작, 종료 절차는 나중에 다시 봐야겠다.. 매우 -_-; 많다.

클래스 로딩 절차는 loading -> linking -> initializing 으로 보자.

2018.02.20

![]()

Class Loader SubSystem

Java’s dynamic class loading functionality is handled by the Class Loader SubSystem. It loads, links and initializes the class when it refers to a class for the first time.

Class Loader SubSystem is responsible for following 3 activities

Java의 동적 클래스 로딩 기능은 클래스 로더 서브 시스템에서 처리합니다. 클래스를 처음 참조 할 때 클래스를로드, 링크 및 초기화합니다.

클래스 로더 서브 시스템은 다음 세 가지 활동을 담당합니다.

  1. Loading

  2. Linking

  3. Initialization

- Loading

Loading 의 의미는 hard disk 로부터 class file을 읽어 들이고, method area로 binary data 저장시킨다. 이런 class 파일들은 JVM의 method area에 아래에 저장됩니다.

저장되는 것은 아래 내용과 같다.

Fully qualified name of class

Fully qualified name of immediate parent class

Methods info

Variable info

Constructor info

Modifiers info

Constant pool info

whether .class file represents class or Interface or enum

.class파일이 로딩된 후에 JVM은 즉시 Heap memory에 로드된 클래스들의 object들이 생성됩니다.

얼마나 많은 클래스 클래스 객체가 JVM에서 생성됩니까? (중요한 면접 질문) 로드 된 모든 유형의 경우 우리 프로그램에서 클래스를 여러 번 사용하더라도 하나의 클래스 객체 만 생성됩니다.

Linking

Linking은 3가지를 수행합니다.

  1. verify (verification)

  2. prepare (preparation)

  3. resolve (resolution)

Linking은 class 또는 interface들을 검증하고 준비시킵니다.

  • that class or interface,

  • its direct superclass,

  • its direct super interfaces, and

  • its element type (if it is an array type), if necessary.

  1. Verification

  • It is a process of ensuring that Binary representation of a class is a structurally correct or not.

  • JVM will check whether the .class file is generated by valid compiler or not.

  • .class file is properly formatted or not.

  • Internally Bytecode verifier is responsible for this activity.

  • Bytecode verifier is a part of Class Loader SubSystem.

  • If the binary representation of a class or interface does not satisfy the static or structural constraints then a VerifyError is thrown. An error thrown is an instance of LinkageError (or its sub class).

* 그것은 클래스의 이원 표현이 구조적으로 정확한지 확인하는 프로세스입니다. * JVM은 .class 파일이 유효한 컴파일러에 의해 생성되는지 여부를 확인합니다. * .class 파일의 형식이 올바르지 않거나 없습니다. * 내부적으로 바이트 코드 검증자가이 활동을 담당합니다. * 바이트 코드 검증자는 클래스 로더 서브 시스템의 일부입니다. * 클래스 또는 인터페이스의 2 진 표현이 정적 또는 구조적 제한을 충족시키지 못하면 VerifyError가 발생합니다. throw 된 오류는 LinkageError (또는 그 하위 클래스)의 인스턴스입니다.
자바가 보안 언어 인 이유는 무엇입니까? (중요한 면접 질문) 바이트 코드 검증자는 자바를 보안 된 언어로 만드는 기능 중 하나입니다. 공격자가 클래스 파일을 수동으로 변경하여 일종의 바이러스를 만들면 바이트 코드 검사기가 해당 클래스 파일을 올바른 컴파일러에서 생성되지 않았 음을 감지합니다. Verfication이 실패하면 java.lang.VerifyError라는 런타임 예외가 발생합니다.

2. Preparation

이 단계에서 JVM은 클래스 수준 또는 인터페이스 수준의 정적 변수에 메모리를 할당하고 기본값을 할당합니다.

초기화 단계에서는 원래 값이 정적 변수에 할당되고 준비 될 때만 기본값이 할당됩니다.

3. Resolution

해상도는 런타임 상수 풀의 기호식 참조에서 구체적인 값을 동적으로 결정하는 프로세스입니다. 간단히 말해서, 우리 프로그램의 심볼 이름을 메소드 영역의 원래 메모리 참조로 대체하는 프로세스입니다.

public class Testing { public static void main(String[] arg) { String s = new String("Pumpkin"); Student s1 = new Student(); } }

위 클래스의 경우 클래스 로더가로드됩니다.

Testing.class

Object.class - 부모 클래스

String.class

Student.class

이 클래스의 이름은 Testing 클래스의 상수 풀에 저장됩니다.

해결 단계에서는 이러한 이름이 메서드 영역의 원래 메모리 수준 참조로 바뀝니다.

런타임 상수 풀 형태로 메소드 영역에 현재로드 된 모든 심볼릭 참조는이 JVM에 의해로드 된 실제 유형으로 해석됩니다.

심볼릭 참조를 확인할 수는 있지만 정의가 충돌하는 경우 IncompatibleClassChangeError가 발생합니다. 메서드 조회가 실패하면 메서드 확인이 NoSuchMethodError를 throw합니다. 메서드의 검색이 성공 해, 메서드가 abstract이지만 Class가 abstract가 아닌 경우, 메서드의 해결로 AbstractMethodError가 슬로우됩니다. 위의 모든 오류는 java.lang.LinkageError 클래스의 하위 클래스입니다.

Initialization

초기화 단계에서 모든 정적 변수는 원래 값으로 할당되고 정적 블록은 부모에서 자식으로 그리고 위에서 아래로 실행됩니다.

로드, 링크, 및 초기화 중에, 에러가 발생했을 경우, java.lang.LinkageError 또는 그 서브 클래스 java.lang.VerifyError를 나타내는 실행시 예외가 발생합니다.

Runtime Data Area

Runtime Data Areas는 JVM이 프로그램을 수행하기 위해 OS로 부터 별도로 할당 받은 메모리 공간이다. 이 역시 JVM의 하위 계층이고 역시 벤더마다 다르지만, 보통의 Runtime Data Areas에 대해 설명하겠다.

Runtime Data Areas는 PC Register, Java Virtual Machine Stacks, Native Method Stacks, Method Area, Heap 이렇게 5개로 나뉜다.

PC Register, Java Virtual Machine Stacks, Native Method Stacks이 3개는 Thread별로 존재하며, 동기화 이슈가 발생하지 않는다. 하지만, 나머지 2개 Method Area, Heap는 모든 Thread가 메모리를 공유하기 때문에 동기화 이슈가 발생한다.

**-PC Register **

보통 CPU가 명령어를 처리 하는 과정에서 수행하는 동안 필요한 정보를 Register라는 CPU내의 기억장치에 저장해 둔다. 이는 CPU에 종속적 일 수 밖에 없다. 그렇기 때문에 자바의 철학을 실현하기 위해서는 이러한 CPU내의 Register의 역할을 JVM상에 논리적인 메모리 영역으로 구현한다.

**-Java Virtual Machine Stacks **

이름답게 Stack으로 구성 되어 있고 Thread별로 현재 수행중인 메소드의 정보를 저장하는 곳이다. 이러한 정보를 Stack Frame이라 하며, Stack Frame은 Local Variable Section, Operand Stack, Frame Data로 나뉜다.

**- Local Variable Section **

메소드의 파라미터 변수, 로컬 변수를 배열에 저장하여 인덱스를 통해 접근한다. Primitive Type의 변수들은 Fixed된 크기로 할당되지만, Object나 배열같은 Reference Type은 가변의 Reference가 저장된다. (자바는 모든 객체를 Reference로 전달 된다는 걸 알고 있을 것이다.)

다시 말해 Object는 Reference가 저장된다. 그러므로 Reference Type의 변수들은 접근을 하기 위해선 저장된 Reference정보를 가지고 실제 객체가 저장되어있는 Heap이라는 공간에 찾아간다. 이는 메모리 점프를 많이 하게 되므로, Primitive Type의 변수보다 비용이 많이 든다.

**- Operand Stack **

이도 Local Variable Section과 같이 Array로 구성되어 있다. Operand Stack은 JVM이 프로그램을 수행하면서 연산을 위해 사용되는 데이터 및 그 결과를 저장 하는 곳이다.

**- Frame Data **

Constant Pool Resolution정보와 Method가 정상 종료 했을때의 정보, Exception 정보들을 저장하고 있다. Constant Pool Resolution은 바로 Method Area에 저장되어 있는 Constant Pool의 Pointer 정보이다.

**- Native Method Stacks **

Java Virtual Machine Stacks와 하며, Native Code로 되어있는 Function을 호출 하기 위해 사용된다. 실행 후 다시 Java Virtual Machine Stacks로 돌아간다.

**- Method Area **

이는 모든 Thread가 공유하기 때문에 동기화 이슈가 발생한다.

이 영역은 로드된 Type(Class나 Interface)을 저장하는 논린적인 메모리 공간이다. 이 공간은 Garbage Collection의 대상이 된다. Method Area의 Type 정보는 Type Information, Constant Pool, Field Information, Method Information, Class Variables, Reference to class (ClassLoader), Reference to class (Class)와 같이 7개로 구성된다.

**ㄴ Type Information **

Full Qualified Name, Type의 super class정보, Type의 Interface인지 class인지, Type의 Modifier(public, abstract, final)

**ㄴ Constant Pool **

Literal Constant, Field, Symbolic Reference

Field가 Constant Pool에 있다는것은 Field는 여러 스레드가 하나의 객체에 접근할 때 동기화 이슈가 발생한다는 뜻이다. (Thread별로 생성되는 JVM Stacks에 Local Variable Section은 동기화 이슈가 발생하지 않는다.)

**ㄴ Field Information **

Field 이름, Data Type, 선언된 순서, Modifier(public, private, protected, static, final, volatile, transient)

**ㄴ Method Information **

Method 이름, Return Data Type, Parameter수, Data Type, 선언된 순서, Modifier(public, private, protected, static, final, synchronization, native, abstract), Bytecode,Stack Frame의 크기, Exception Table

**ㄴ Class Variable **

static으로 선언된 변수이다. 동기화 문제가 발생하며, final로 선언된 경우 상수로 취급하여 Constant Pool에 저장된다.

**ㄴ Reference to Class (ClassLoader) **

Type이 어떤 ClassLoader를 경유하여 로딩되었는지 알 수 있다.

**ㄴ Reference to Class (class) **

Type가 로드되면 java.lang.class class의 Instance가 하나 생성된다. 이는 RTTI(Run Time Type Information)으로 런타임시에 Class의 정보를 알아올 수 있다. (Reflection)

**- Heap **

모든 Thread가 공유하는 공간이므로 동기화 이슈가 발생하며, 실제 Object와 Array 객체가 저장되는 곳이다. JVM이 Heap영역에 메모리를 할당하며, Garbage Collection을 통해 메모리를 해제한다.

참고 사이트

http://cleancodes.tistory.com/6

http://codepumpkin.com/class-loader-subsystem-jvm-internals/#Linking

2018.02.28

https://www.cubrid.org/blog/understanding-java-garbage-collection/

위 내용 읽어보자.

This article is licensed under CC BY 4.0 by the author.