JVM구조

0

소개

Java를 계속 사용해오면서 JVM의 구조에 대해서 어느정도 알고 있지만 스스로 조금 더 자세히 알고싶어 자료들을 찾아보며 글을 정리한다.
이번 글에서는 JVM구조에 대해서 보고 각각의 역할들에 대해 정리할 것이다.

JVM이란

JVM이란 자바 가상 머신(Java Virtual Machine) 이다.
자바 어플리케이션들이 OS에 독립적으로 구동된다는 말을 자바를 공부했다면 분명 들어봤을 것이다. OS에 상관없이 실행될 수 있는 이유는 JVM이라는 레이어가 OS위에 한가지 더 있기 때문이다.

JVM이 존재함으로서의 장단점

C언어나 C++로 코딩해서 윈도우에서 컴파일한 결과물이 리눅스에서는 오류가 발생하는 등의 문제가 발생한다. 이런 경우 크로스 컴파일러를 통해 각 운영체제에 맞게 크로스 컴파일을 해주어야하는 문제가 있다.

자바는 JVM이라는 것이 존재하여 JVM이 javac로 컴파일된 바이트코드를 실행하게 되어있다. 따라서 개발자가 신경써야 할 것은 열심히 자바 문법에 맞게 코딩하고 운영체제에 맞는 JVM만 설치해놓으면 되는 것이다.
그리고 장점이 또 있는데 JVM에 GC(Garbage Collector)란 것이 있어서 메모리를 할당받고 메모리를 수거하는 일을 GC가 자동으로 해준다!! 두둥
C언어 할 때가 생각난다 malloc을 통해서 메모리를 동적할당받고 받은 메모리는 free를 통해 반환해 주어야 했던 복잡함이.....
사실 개발자가 정말 메모리를 잘 관리할 수 있다면 GC같은 것도 필요없이 개발할 수 있을 것이다. 하지만 어플리케이션이 복잡해지고 무수한 기능들이 만들어지는데 그것을 정말 잘 관리할 수 있는 사람이 몇이나 될까? 나는 그냥 지나가는 흔한 개발자라 이런 것까지 신경쓰면서 하면 너무나 힘들 것같다.
그래서 최근의 이슈가되는 언어들이나 멀티 플랫폼을 지원하는 언어들이 대부분 너희는 이런 것들은 신경쓰지말고 어플리케이션 잘 만드는 것에만 집중해라는 방향으로 발전된 것 같다.

이렇게 보면 JVM이 굉장히 좋아보인다. 장점만 있으면 얼마나 좋을까..
메모리도 자동으로 관리해주고 OS도 신경 안쓰고 자바로 구조 잘짜고 코딩만 잘하면 될 수 있도록 해주는 대신 다른 언어들에 비해 JVM이라는 기본적인 레이어가 하나 더 들어가기 때문에 메모리 리소스를 더 먹는다.
그리고 GC가 메모리를 자동으로 수거해준다고하는데 굉장히 다양한 어플리케이션이 만들어지고 있는데 GC의 기본 알고리즘이 모든 어플리케이션에 효율적으로 작동할까? 그것은 모르는 일이다. 그래서 우리는 항상 자동으로 해준다는 말에 의심을 품어야한다고 생각한다. GC또한 최적화할 수 있는 방법을 제공하니 추후에 포스팅해볼 생각이다.

계속 기술에 대한 의문을품고 깊게 들어가려하다 보니 다른말을 계속 하게 될거 같아 이제 JVM의 구조를 보자.

JVM구조

진짜 JVM 구조를 알아보자.

간단하게 그려보았는데 하나하나 보면서 알아보자.

먼저 우리가 자바로 소스코드를 작성하고 실행하기 위해서는 JDK를 설치할 때 있는 javac를 통해 바이트코드 변환을 해야한다. 이클립스나 인텔리제이는 툴에서 이 과정을 자동으로 해주기 떄문에 우리가 편하게 사용하는 것이다.

컴파일을 하고 나면 .class 예를들어 Person 클래스의 Person.class 파일이 만들어지게 된다. 이 파일에 바이트코드란 것이 있는 것이다. 여기까지가 컴파일 단계이다.

Class Loader

이때부터 실행 단계이다. 실행할 때에는 java 명령어를 통해 실행하게된다.
실행시 Class Loader는 바이트코드를 읽어서 클래스 정보를 Runtime Data Area에 적재하는 역할을한다.

Execution Engine

Execution Engine은 메모리에 적재된 바이트코드를 실제 기계어로 번역하여 실행하는 엔진이다. 실행하는 방식에는 바이트 코드를 한줄한줄 읽어 실행하는 인터프리터 방식이 있고 자주 쓰이는 바이트코드를 기계어로 변환시켜 놓고 사용하는 JIT(Just In Time)방식이 있다.
당연히 프로그램을 실행할 때 하나하나 읽어서 번역 후 실행하면 실행시간이 오래걸릴 것이다. JIT는 미리 번역해놓고 쓰는 방식이기 때문에 인터프리터 방식보다 실행속도가 빠르다는 장점이 있다. 하지만 미리 컴파일하는 시간이 오래 걸린다.
조금 알아본바에 의하면 JIT 덕분에 성능이 많이 상승되었다고 알고있다.

GC(Garbage Collecor)

위에서도 말했듯이 GC 알고리즘에 따라 메모리를 관리해주는 장치? 프로그램이라고 할 수 있겠다. 우리가 메모리에 관해 완전히 까진 아니지만 신경쓸필요 없이 편하게 코딩할 수 있게 해주는 장치이다. GC에 대해서는 다음번에 조금 더 깊게 볼 것이기 때문에 자세히 설명하지는 않는다.

Runtime Data Area

Runtime Data Area는 런타임시에 관리되는 메모리 영역을 의미한다.

Method Area

Method Area는 클래스의 멤버 변수, 메소드, Type 정보, Contant Pool, static, final 변수 등이 존재하는 곳이다.

Heap Area

동적으로 생성된 오브젝트 인스턴스와 배열이 저장되는 공간으로 GC가 발생할 경우 Heap 영역의 메모리를 관리한다.

Stack Area

Stack Area는 PC Register와 같이 각 스레드마다 생성되는 공간이다.
지역 변수나, 파라미터 등을 사용하면 이 영역에 생성된다.
또한 Heap 영역에서 할당된 메모리 공간에 대한 레퍼런스는 Stack에 저장된다.
예를 들어 메소드에서 반복문이나 분기문을 사용 할때 int a = 1;과 같이 선언하는 변수들은 스택에 저장된다.

PC Register

PC(Program Count) Register는 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있다.
이게 존재하는 이유는 당연히 우리가 여러 스레드를 사용할경우 동시성을 처리할 때 Context Switching이 발생하면 해당 스레드에서 어느 부분을 실행하고 있었는지 알아야한다. 그래야 이어서 실행하게 될 것이다.

Native Method Stack

Native Method Stack은 자바 외의 네이티브 언어로 작성된 코드를 위한 영역이다.
예를들어 C, C++로 코딩된 결과물을 JVM에서 실행하고 싶을 때 사용할 수 있는 공간이다.

정말 간단하게나마 내가 아는 지식과 조사한 자료를 기반으로 적어보았는데 제대로 알려면 많은 시간이 걸릴 것이다. 일단 이렇게 정리하고 한개 한개 더 자세히 포스팅해볼 생각이다.

Reference

https://ko.wikipedia.org/wiki/%EC%9E%90%EB%B0%94_%EA%B0%80%EC%83%81_%EB%A8%B8%EC%8B%A0

0개의 댓글