[JAVA] JVM의 메모리 구조 및 동작 원리

DyungE_100·2022년 3월 28일
0

JAVA

목록 보기
1/3

1. JVM이란?

JAVA Virtual Machine(자바 가상 머신)의 약자로, 자바 바이트 코드를 실행할 수 있는 주체이다.
자바 바이트 코드는 운영체제(OS)에 독립적이며 모든 JVM은 규격에 정의된 대로 자바 바이트 코드를 실행한다.
또한, JVM은 자바 애플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행한다.

2. JVM의 메모리 구조

응용 프로그램이 실행되면, JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 여러 영역으로 나눈다.

- 1. Class Loader

java에서 소스를 작성하면 .java파일이 생성되며 이 소스를 컴파일하면 .class파일(ByteCode)이 생성된다.
이렇게 생성된 .class파일들을 엮어서 JVM이 운영체제로 할당 받은 메모리 영역인 Runtime Data Area로 적재(Loading)한다.

- 2. Excution Engine

메모리에 적재된 클래스(ByteCode)들을 기계어(BinaryCode)로 변경하여 명령어 단위로 실행하는 역할을 한다.
인터프리터(Interpreter)방식과 JIT(Just-In-Time) 컴파일러를 사용하는 두 가지 방식이 있다.

  • Interpreter : 명령어를 하나씩 실행하는 대화형식 컴파일. 파이썬이 대표적인 인터프리터 언어.
  • JIT(Just-In-Time) Compiler : 적절한 시간에 전체 바이트 코드를 네이티브 코드로 변경해서 실행하므로 성능이 인터프리터보다 속도 면에서 성능이 더 좋다.

- 3. Garbage Collector

Garbage Collector(GC)는 Heap 메모리 영역에 적재된 객체들 중 참조되지 않는 객체들을 탐색(애플리케이션이 생성한 객체의 생존 여부) 후 제거하는 역할을 한다. GC가 역할을 수행하는 시간을 정확히 언제인지 알 수 없다. GC의 또 다른 특징으로는 GC가 수행되는 동안 GC를 수행하는 쓰레드가 아닌 다른 모든 쓰레드가 일시 정지된다.

- 4. Runtime Data Area

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.
이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack 으로 나눌 수 있다.

3. Runtime Data Area 영역 분류


1. Method Area(메소드 영역)

클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보 같은 field 정보들과 메소드의 이름, return타입, 파라미터, 접근 제어자 정보 같은 method 정보들, type정보, Constant Pool, static변수, final class변수 등이 생성되는 영역.

2. Stack Area(스택 영역)

지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값, 메서드 호출 등 임시적인 데이터들이 생성되는 영역.
정적 메모리 할당이 이루어지는 장소로 Heap 영역에 동적 할당된 값에 대한 참조를 얻을 수 있다.
ex) Person p = new Person(); 에서 Person p는 Stack 영역, new Person();은 Heap 영역에 할당된다.

3. PC Register

쓰레드가 생성될 때마다 생성되는 영역으로 쓰레드마다 하나씩 존재한다. 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역이다. 이것을 이용하여 쓰레드를 돌아가면서 수행할 수 있도록 한다.

4. Native Method Stack

자바 외의 언어로 작성된 Native 코드를 위한 메모리 영역. 보통 C/C++ 등의 코드를 수행하기 위한 Stack이다.

5. MetaSpace

애플리케이션의 클래스나 메서드 정보, 또는 static으로 정의된 멤버 변수가 저장된 영역. 이전 버전의 Permanent영역에 해당함.

6. Code Cache

JIT(Jus-In-Time) 컴파일러가 데이터를 저장하는 영역으로, 자주 접근하는 '컴파일된 코드 블록'이 저장된다.
이곳에 저장된 코드는 기계어로 이미 변환된 채 Cache되어 있어서 빠르게 실행할 수 있다.

7. Shared Library

애플리케이션에서 사용할 공유 라이브러리가 기계어로 변환된 채 저장된 영역. 해당 OS에서 프로세스당 한 번씩 로드된다.

8. Heap Area(힙 영역)

new 키워드로 생성된 객체와 배열이 생성되는 영역(즉, 인스턴스 변수(Instance Variable)가 생기는 영역). 메소드 영역에 로드된 클래스만 생성이 가능하고, GC가 참조되지 않는 메모리를 확인하고 제거하게 된다.

Heap영역의 분류

heap 영역은 현재 4개의 영역으로 나뉘는데 GC를 더욱 효율적으로 사용하기 위함이다.
JDK7까지는 permanent 영역이 heap에 존재했지만 JDK8부터는 permanent 영역은 사라지고 일부가 "meta space" 영역으로 변경되어 Native Stack 영역에 포함되었다.

GC는 Minor GCMajor GC로 나뉜다.

Minor GC : New 영역에서 일어나는 GC

  1. 최초로 객체가 생성되면 Eden 영역에 생성된다.
  2. Eden 영역에 객체가 가득 차면 첫 번째 GC가 일어난다.
  3. survivor1 영역에 Eden 영역의 메모리를 그대로 복사하고, 해당 영역을 제외한 다른 영역의 객체를 모두 제거한다.
  4. Eden 영역의 메모리도 가득 차고 survivor1 영역의 메모리도 가득 차게 되면, Eden 영역에 생성된 객체와 survivor1 영역에 생성된 개체 중 참조되고 있는 객체가 있는 지를 검사한다.
  5. 참조되고 있지 않은 객체를 제외한 참조되고 있는 객체만 survivor2 영역에 복사한다.
  6. survivor2 영역을 제외한 다른 영역의 객체들을 제거한다.
  7. 위의 과정 중 일정 횟수 이상 참조되고 있는 객체들을 survivor2 영역에서 Old 영역으로 이동시킨다.

Major GC (Full GC) : Old 영역에서 일어나는 GC

  1. Old 영역에 있는 모든 객체들을 검사하며 참조되고 있는지 확인한다.
  2. 참조되지 않은 객체들을 모아 한 번에 제거한다.
    (이 때 Minor GC보다 시간이 많이 걸리고 실행 중 GC를 제외한 모든 쓰레드는 중지된다.)
    Major GC가 일어나게 되면 Old 영역에 있는 참조가 없는 객체들을 표시하고 그 해당 객체들을 모두 제거하게 된다.
    그 후 Heap 영역은 빈 공간이 생기는데 이 부분을 없애기 위해 재구성을 시행한다. 이 때 메모리를 옮기는데 다른 쓰레드가 메모리를 사용해버리면 안되므로 모든 쓰레드가 정지하게 되는 것이다.

출처 : 책<JAVA의 정석>,
https://jeong-pro.tistory.com/148,
https://velog.io/@agugu95/%EC%9E%90%EB%B0%94%EC%99%80-JVM-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0,
https://limkydev.tistory.com/51,

0개의 댓글