본문 바로가기

Programinng/Java

자바 JVM (Runtime Data Areas)

자바의 기본서적을 보면 자바는 '플랫폼에 독립적이다.'라고 설명되어있다. 하지만 그 설명이 매우 미약하여 대부분의 사람들은 왜 플랫폼에 독립적인지 잘 모른다.


자바의 철학이 바로 'Write Once, Run Everywhere' 인데, 이는 한번 작성된 프로그램은 어디에서나 실행 가능해야 한다라는 뜻이다.  이 철학을 실현하기 위해 가장 중요한 것이 바로 JVM이다. 


사용자가 .java 파일을 작성하여 javac로 컴파일을 하게되면 .class라는 확장자를 가진 파일이 생긴다. 이는 JVM(Java Virtual Machine)이 읽을 수 있는 Bytecode로 해석된 것이며, 이 class파일을 가지면 JVM이 설치된 그 어느 곳에서도 사용이 가능하다는 것을 의미한다.  이로써 자바는 플랫폼에 독립적이다라고 말할 수 있다. (글쎄 사실.. JVM이 설치 되어 있어야 한다는 전제하에 있어서이다. 이는 어쩌면..눈 속임일 수도...ㅠㅠ)


쉽게 말해 JVM은 바로 자바의 바이트 코드를 해당 컴퓨터의 명령어로 해석해주는 프로그램이라고 할 수 있다. JVM는 하나의 스펙, 개념과 같으며 이를 개발하는 벤더마다 기본적인 개념만 같을 뿐, 구현 방법은 모두 다르다. 보통 Hotspot JVM이라는 것이 자바에 기본 내장된 JVM이며, 가장 많이 쓰이는 JVM이기도 하다.


그렇다면 Runtime Data Areas는 무엇일까?..


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을 통해 메모리를 해제한다.