Java 동작원리 및 개념

이진영·2023년 5월 25일
0

JAVA 기초

목록 보기
1/9
post-thumbnail

Java를 공부한다면 아마도 가장먼저 짚고 넘어가는 개념이지 않을까 싶다. 그렇기에 나 또한 정리를 해나갈려고 한다. 이미 정말 좋은 글들이 많지만 필자는 정리를 함으로서 내 것으로 만들어 가기 위해 글을 작성할려고 한다.

JAVA의 탄생 배경


먼저 언어를 제대로 알기 전에 이러한 것을 누가 만들었는지는 정말 창시자에 대한 예의이지 않을까 싶다. 왜냐면 이러한 언어를 통해서 가치를 주는 행위는 정말 좋은 생위라고 생각 하기 때문이다.

그렇다면 이러한 언어는 누가 만들고, 왜 탄생했을까?

JAVA는 1991년 썬 마이크로시스템즈의 제임스 고슬링이라는 사람과 다른 연구원들이 개발한 프로그래밍 언어이다.

발생 배경은 정말 사소한 불편함 속에서 발생하게 되는데 이는 C/C++의 특성상 여러 하드웨어를 커버하기에 같은 기능의 소스코드를 각 하드웨어에 맞게 작성해야하는 번거로움을 통해서 만들어 졌다고 한다.

그렇기 때문에 JAVA는 환경에 제한이 없습니다. 이는 CPU, OS에 제한없이 독립적인 환경을 제공합니다.

이러한 환경에 제약이 없는 큰 장점은 정말 폭발적인 인기를 얻어갔기 때문에 지금까지의 인기를 얻어 갈수 있게 됐습니다.

JAVA의 동작원리


먼저 간단하게 설명 후 그림을 통해 제대로 알아보려고 한다. .java 파일을 .javac(컴파일러)가 .class로 바꾸어 기계어로 변환한다. 이후 .class파일은 JVM을 통해 실행이됩니다.


위 그림을 보면 어떤식으로 동작이 되는지 한 눈에 들어올 것이다.

  1. 작성한 자바소스(java source)를 작성하면 .java로 저장하게 되는데
  2. 이를 java compiler를 통해 자바 바이트 코드 즉 class파일로 변환하게 도움을 주게 됩니다.
  3. 그 다음 jvm를 통해 실행을 하게 되는데 이는 Class Loader를 통해 실행이 가능해집니다.
여기서 잠깐!!

java에서는 3가지의 J약자를 제공한는 특징을 공부하다보면 접하게 될 수 있다. 필자 또한 알게 됐기 문에 여기에 적어둘려고 한다.
JVM : 자바 가상환경으로서 컴파일러를 통해 나온 결과를 바이트코드를 실행시켜주는 가상 머신이다.
JRE : Java Runtime Environment의 약자로, 자바 실행환경을 의미한다. 그런 의미는 실행에 필요로 하는 각종 라이브러리를 담고 있다.
JDK : Java Development Kit의 약자로, 자바 개발 키트를 의미한다.

JVM 구조와 동작


여기 까지 알아본 바로는 JVM은 자바 프로그램 실행환경을 만들어 주는 소프트웨어입니다.

모듈

JVM은 총 4가지의 모듈로서 구성이 되는데 이는 Class Loader ,Execution Engine ,Runtime Data Area ,garbage collector 가 있습니다. 이를 차근차근 알아보도록 하겠습니다.

Class Loader

먼저 첫 번째인 Class Loader .class 파일을 JVM에 올려주고, 검증, 초기화해주는 역할을 하고 있습니다. 이는 총 3가지의 과정을 거치게 됩니다.
1. 클래스 파일을 JVM에 올려주는 과정 Loading
2. 해당 파일을 사용하기 위해 검증을 하고 기본값으로 초기화하는 과정을 Linking
3. 클래스 파일을 이용해 static변수 등을 초기화하는 과정을 Initialization

이러한 과정들이 있지만 이러한 각 과정 속에서도 여러가지의 과정이 있습니다.

Loading 과정


Loading은 여러가지로 나뉘어서 동작을 하는 과정이 있습니다. 그러한 이유는 class간에 충돌을 방지할 수 있고 사용하지 않는 class를 loader에서 지움으로서 효율적으로 사용이 가능하기 때문입니다.

간단한 구성요소 입니다.

bootstrap class loader

다른 모든 class loader의 부모가 되는 class loader이며, rt.jar를 포함하여 구동시키기위 한 가장 필수적인 라이브러리의 클래스들을 JVM에 탑재하게 됩니다. 그렇기에 네이티브 코드로 쓰여있습니다.

다음은 담당 클래스 파일들을 탑재하는 내용입니다.

[Opened /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
[Loaded java.lang.Object from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/rt.jar]
...중략...

extension class loader

그 다음으로는 우선순위를 가지는 class loader로서 localedata, zipfs등 다른 표준 핵심 클래스 라이브러리들을 JVM에 답재하는 역할을 하고 있으며, 이는 $JAVAHOME/jre/lib/ext_ 라는 경로에 있습니다.

application class loader

-> System Class Loader라고도 불리며, class path에 있는 클래스들을 탑재하는 역할을 합니다. 개발자들이 자바 코드로 짠 클래스 파일들을 JVM에 답재하는 역할을 하고 있습니다.

마찬가지로 담당 클래스 파일들을 탑재하는 내용입니다.

...중략...
[Loaded UserClass from file:/home/hybeom/OTC/java8/src/]
...중략...

또한 위의 각각의 Class Loader들을 모두 거치고 나서도 찾지 못하는 경우가 있다. 이는 ClassNotFoundException이라느 예외를 던지게 됩니다.(이는 개발자에게 정말 익숙한 예러라고 볼수 있는데 이러한 Class Loading 과정에서 예외를 던지는게 왠지 모르게 지식을 탄탄히 쌓아 갔다고 볼 수 있어서 매우 기분이 좋다.ㅎㅎ)

아래 출력은 개발자라면 한번쯤 보는 에러이다.ㅋㅋㅋ

...중략....
java.lang.NoClassDefFoundError: UserClass
    	at Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: UserClass
    	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
...중략...

이러한 로드된 클래스들을 검증하는 역할 또한 매우 필요로한 존재인데 이러한 역할은 Linking이라는 곳에서 파일들을 Verification, Preparation, Resolution 세 가지의 단계로 거쳐서 검증을 하게 됩니다.

  1. Verification
    클래스 파일이 유효한지를 확인하는 과정입니다. 만약 구현되지 않았을 경우는 VerifyError를 던지게 됩니다.
  2. PreParation
    클래스 및 인터페이스에 필요한 static field 메모리를 할당하고, 이를 기본값으로 초기화합니다.
  3. Resolution
    Symbolice Reference 값을 JVM의 메모리 구성 요소인 Method Area의 런타임 환경을 통하여 Direct Reference 라는 메모리 주소 값으로 바꾸어 줍니다.

이러한 Linking 과정을 거치면 Initialization 단계에서는 클래스 파일의 코드를 읽게 됩니다. Java 코드에서의 Class 와 Interface의 값들을 지정한 값들로 초기화 및 초기화 메서드를 실행하는데 여기서 JVM은 멀티 쓰레딩으로 작동하기 때문에 같은 시간에 한 번에 초기화를 하는 경우 동시성을 고려해주어야 합니다.


Execution Engine
메모리에 적재된 클래스들을 기계어로 변경항여 명령어 단위로 실행합니다.
바이트 코드를 운영체제에 맞게 해석해주는 역할을 수행합니다. 실행엔진이 바이트 코드를 명령어 단위로 읽어서 수행하는데 크게 두 가지 방식이 상용된다고 한다.

  • 인터프리터(Interpreter)
  • JIT(Just In Time)

Interpreter

Interpreter는 자바의 가장 큰 장점을 가능하게 만드는 역할을 합니다. 즉 플랫폼에대해서 독립적이고 이식성이 높게 가능하게 해줍니다. 각 환경에 맞는 인터프리터가 바이트 코드를 실행하기 때문에 Window, Linux, Mac 어디든 실행될 수 있습니다. 인터프리터는 바이트 코드를 읽고 운영체제가 실행할 수 있도록 기계어로 변경하는 역할을 수행합니다. 하지만 이러한 바이트 코드를 읽을 경우 속도 문제가 발생합니다. 매번 코드 각 줄을 읽고 번역하기 때문입니다.

JIT

반면 JIT는 Interpreter의 단점을 해결하기 위해 고안된 해결법이라고 볼 수 있습니다. 자주 실행되는 바이트 코드 영역을 런타임 중에 기계어로 컴파일하여 사용하는데 이는 Interpreter와 같이 NativeCode로 변역을 담당하지만 매번 코드를 번역하지 않고 자주 반복되는 코드는 Native Code로 변역하여 Native Method Stack에 저장해두었다가 같은 코드가 나왔을 때 캐싱을 통해 이미 번역된 Native Code를 사용하여 효율성이 높습니다.


Runtime Data Area

JVM이 프로그램을 싱행하기 위해 OS별로 저장하는 공간입니다.

Runtime Data Area는 크게 다섯 가지로 구분이 된다. 하지만 여기서 크게 두 가지로 나뉠 수 있다.

  • PC Register , JVM stack , Native Method stack은 Tread별로 생성
  • Heap , Method Area 모든 Thread가 공유한다.

그렇다면 세세하게 하나씩 짚어 나가 보자!!

Method Area

static 변수, 그리고 모든 메소드에 사용되는 데이터와 같은 Class 메타데이터가 저장되면서 JVM 구동시 해당 영역이 생성되고 JVM이 종료시 해제된다. 또한 해당 영역은 원래 Heap영역에 포함되지만 Java8 이후에는 Metaspace라는 OS가 관리하는 영역으로 옮겨지게 된다.

Heap Area

Java로 구성된 인스턴스, 배열등이 저장된다. 모든 Java Stack 영역에서 참조되어 Thread간 공유가 되는데 여기서 해당 영역이 가득차게 된다면 OutOfMemoryException를 발생시킨다. 또한 이러한 오류는 Garbage Collection의 대상이 되는 영역이기 때문에이다.

Java Stack

Java의 메소드가 호출될 때 사용되는 메모리 공간/ 변수, 오퍼레이션, Reference 정보 등이 저장됩니다.

PC Register

Thread별로 동시에 동작할 수 있도록 메모리 주소를 저장하는 공간

Native Method Stack

시스템 자원을 사용하거나 Java로 구성된 코드만 사용될 수 없는 경우, 다른 프로그래밍 언어로 작성된 메소드를 호출 시 사용되는 영역


garbage collector
Java의 Heap영역에서의 참조되고 있지 않는 객체들의 메모리를 할당 해제하는 과정이라고 볼 수 있습니다.

이때는 크게 4가지의 특징을 가지고 있습니다.

  • 명시적으로 불필요한 데이터는 null로 선언
  • System.gc()메소드로 GC를 할 수 있으나 프로그램 성능에 큰 영향을 미침
  • 영억에 따라 Minor GC, Major GC로 나뉨
  • GC과저에서 중요한 개념을 Reachability, Stop-the-world

GC에서도 정말 깊게 파고들면 많은 정보와 관련지식을 가지고 있어야 한다...ㅠㅠ
하지만 필자는 크게 중요한 개념만을 알고 추후에 좀 더 세세하게 지식을 게시할 예정에 있다.

Reachability

GC 역할 자체가 참조되고 있지 않는 객체들의 메모리 할당을 해제하는 과정인데 Reachability의 역할은 해당 객체가 유요한지 아닌지를 판별하는 역할을 한다. 어떻게 하냐?!! 유요한 참조가 있으면 reachable , 아니라면 unreachable로 구분한다. 구분을 했다면 unreachable에 속한 객체를 메모리 할당을 해제를 한다.

Stop-the-world

GC를 수행하기 위해서 JVM이 애플리케이션 실행을 멈추는 행위를 말한다. 즉 Stop the world가 발생을하면 GC Thread를 제외하고 기존 Thread의 실행을 멈춘다. 완료 후에는 다시 애플리케이션을 실행합니다.


참조 목록

https://domean.tistory.com/199

https://velog.io/@musimco/GC-reachability-Java-Reference

https://jithub.tistory.com/40

https://coding-factory.tistory.com/827

https://velog.io/@impala/JAVA-JVM-Execution-Engine

profile
내가 공부한 것들을 적는 공간

0개의 댓글