ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 자바 프로그램 실행과정(JDK / JRE / JVM)과 자바 메모리 구조의 이해
    IT/개발(자바, 서블릿, 스프링 등) 2019. 9. 22. 01:06

    오늘은 굉장히 폭 넓은 이야기 주제를 가지고 왔다.

    자바 애플리케이션 실행과정과 메모리 구조까지 설명을 하려고 한다.

    평소에 굉장히 궁금해했던 부분이었는데, 드디어 공부를 하게 돼서 속이 후련하다 =>

     

    자 그럼, 자바 프로그램이 실행되는 과정의 이야기를 시작해보자!

     

    프로그래밍을 할 때, 우리는 (Edit -> Compile -> Run) -> (Edit -> Compile -> Run) -> ... 

    (Edit - Compile - Run) 사이클을 거친다.

    나는 자바 개발자이므로 자바로 예를들어 각각의 과정을 설명하겠다.

     

    Edit 메모장에 자바 소스코드를 작성하는 것.
    Compile 컴파일러로 자바코드(.java)를 바이트코드(.class)로 해석하는 것.
    Run 바이트코드를 실행하는 것.

     

    이러한 과정을 거쳐서 자바 애플리케이션이 실행된다.

    위의 사이클을 모두 할 수 있는 환경을 통합개발환경(Intergrated Development Environments, IDEs)이라고 부른다.

    예로 IntelliJ나 Eclipse 등이 있다.

    에디터, 컴파일러, 실행기, 디버거 등 우리가 개발 로직구현에 집중할 수 있도록 다양한 기능을 제공해준다 :)

     

    지금부터 이 사이클을 조금 더 자세히 살펴볼텐데, 자바 앱을 개발할 때 가장 먼저 다운 받는 JDK의 구성요소를 알아보며 실행과정을 살펴볼 것이다.

    JDK에는 무엇이 포함되어 있어서 우리가 자바 개발을 할 수 있도록 도와주는 것일까?

    내가 직접 열심히 그린 (ㅎㅎ) 아래 사진을 살펴보자.

     

     

    평소에 많이 들어봤을 JDK, JRE, JVM은 위의 사진과 같이 서로 포함관계로 되어있다.

    JDK > JRE > JVM 순서이다.

    즉, JDK를 다운받으면 JRE와 JVM도 설치가 된다.

     

     1. JDK(Java Development Kit) 

     

    JDK(자바 개발 도구)는 우리가 자바를 개발할 때 필요한 소프트웨어 번들을 가지고 있다.

    많은 기능을 가지고 있지만, 자바 컴파일러와 JRE에 대해 설명하겠다.

     

    자바 컴파일러인 javac는 자바로 작성된 코드(.java)를 jvm이 읽을 수 있는 바이트코드(.class)로 해석해주는 툴이다.

    우리가 IDEs인 인텔리제이에서 앱을 실행할 때에도 내부적으론 이 도구를 이용해서 컴파일을 하게 된다.

     

    우리에게 이젠 jvm이 읽을 수 있는 바이트코드가 있다.(여기까지를 컴파일 타임 환경이라고 부른다.)

     

     

     2. JRE(Java Runtime Environment) 

     

    JRE(자바실행환경)은 자바 프로그램이 실행할 수 있는 환경을 제공해준다.(여기에서부터 런타임 환경이라고 부른다.)

     

    Bytecode Verifyer는 우리가 위에서 만든 바이트코드가 안전한지 검사한다.

     

    Java Class Libraries는 미리 정의되어 있는 .class 파일들을이다.

    java.util.ArrayList 패키지를 import 해야 우리는 ArrayList 객체를 생성할 수 있다.

    이런 java.util, java.lang 등의 패키지들이 Java Class Libraries에 미리 정의되어 있어서 동적으로 가져와 사용할 수 있는 것이다.

     

    마지막으로 Class Loader는 우리가 위에서 생성한 바이트코드와 실행하려는 프로그램에서 필요한 미리 정의되어 있는 .class 파일들을 동적으로 메모리에 로드한다.

     

     

    * Runtime Data Area는 JVM이 OS로부터 할당 받은 메모리 공간이다. 아래에서 자세히 다룰 예정이다.

     

     3. JVM(Java Virtual Machine) 

     

    마지막으로 JVM(자바 가상 머신)이다.

    우리가 자바 코드를 바로 (바이트코드도 기계어이지만, 컴퓨터가 이해하는 더 하위의)기계어로 바꾸지 않은 이유가 있다.

    바이트코드라는 중간언어로 바꾼 이유는 JVM이 바이트코드를 읽기 때문이다.

     

    이 때 JVM 내에 있는 자바 인터프리터와 JIT 컴파일러(Just-In-Time Compiler)가 사용이 된다.

    인터프리터는 실시간 해석기이기 때문에 반복 되는 코드가 있을 때 효율이 떨어진다.

    그래서 자주 사용되는 코드가 있을 땐 JIT 컴파일러로 컴파일을 해두는 것이다.

    인터프리터가 동작을 하다가 컴파일러로 컴파일 해둔 부분을 마주치면 미리 컴파일 해둔 기계어를 참고하므로 더욱 빠르게 번역하여 실행할 수 있게 된다.

     

    마지막으로 Garbage Collector.

    C 개발자와 다르게 Java 개발자는 메모리 관리를 따로 할 필요가 없다.

    만약, List<String> list = new ArrayList(); new 키워드를 이용해 객체를 생성했다고 가정하자.

    이렇게 동적으로 생성된 인스턴스는 (뒤이어 우리가 공부하게 될) 힙영역에 공간을 할당 받는다.

    그리고 우리가 더이상 사용하지 않아서 무엇도 위의 list를 참조하지 않을 때, JVM의 가비지 컬렉터가 힙영역의 공간에서 해지해준다.

     

     

    지금까지 JDK의 구성요소를 살펴보면서, 자바 프로그램이 어떻게 동작할 수 있었는지 알아보았다.

    다음으론, 자바의 메모리 구조에 대해서 알아보겠다.

     

    모든 프로그램은 Windows나 Ubuntu와 같은 OS의 제어를 받는다.(지뢰찾기 게임도 실행이 되려면 os의 제어를 받아서 메모리에 올라간 뒤, 실행이 된다.)

    JVM도 소프트웨어 프로그램이므로, OS의 제어 하에 메모리에 올라가서 실행이 된다.

    OS가 JVM에게 메모리를 제공해주고 실행을 하면, JVM이 클래스 로더가 동적으로 올려주는 바이트코드를 해석하고 실행한다.

     

     

    그러므로 JVM은 OS의 제어가 필요하기 때문에 OS에게 종속되지만,

    자바 실행파일은 JVM이 있다면 어디에서나 실행이 될 수 있으므로 OS에게 종속되지 않는다.

    따라서 개발자는 한 번만 프로그램을 작성하면, 모든 운영체제에서 같이 사용할 수 있는 장점이 있다!

    다만, OS가 바로 실행하는 것이 아니고, JVM이라는 해석기를 한 번 더 거치기 때문에 프로그램 실행 속도 저하라는 단점이 있다.

     

     

    이처럼, JVM이 OS로부터 할당 받은 메모리 공간을 Runtime Data Area라고 부른다.

    JVM은 이 공간을 5개의 공간으로 나누어서 사용하고, 한번에 모든 class 파일의 데이터를 올려두는 것이 아니라, 동적으로 필요한 데이터를 올려두며 실행한다.

     

    메모리 공간 이름 저장하는 데이터 메모리에 로드 메모리에서 해제 스레드
    Method(Static, Class) Area

    클래스와 인터페이스에 대한 정보.

    멤버 변수(필드), 클래스 변수(static 변수), 생성자, 런타임 상수 풀(Constant Pool).

    JVM 시작시 메모리에 로드. 프로그램 종료시까지 존재. 모든 스레드에서 공유.
    Heap Area new 연산자로 생성된 객체를 저장.

    런타임에 동적으로 할당하여 사용하는 영역.

    더이상 객체를 참조하지 않을 때 가비지 컬렉터로 할당 해제. 모든 스레드에서 공유.
    Stack Area 메서드, 지역변수, 매개변수, 리턴 값, 연산 시 일어나는 값 임시로 저장.

    중괄호 '{}' 호출시마다 각각의 Stack Frame 생성.(Push Frame)

    중괄호 '{}' 실행이 종료되면 프레임 별로 삭제.(Pop Frame) 각 스레드마다 존재.
    PC Register 현재 수행 중인 JVM 명령어 주소를 가짐.     각 스레드마다 존재.
    Native Method Stack Area

    자바 외 언어로 작성된 네이티브 코드를 위한 stack.

    자바에서 c/c++등의 코드를 수행하기 위해서 JNI(Java Native Interface)를 사용하는데, 그 코드를 수행하기 위한 스택.

    Native Interface 호출 시 생성. Native Interface 종료 시 해제. 각 스레드마다 존재.

     

     

    이제는 자바가 어떻게 동작이 되는지, 메모리 구조는 어떻게 되어 있는지 알게 되었다! 

    조금 더 세부적인 사항은 차차 알아가며 업데이트해야지. =)

     

     

     

     

     

     

    이 블로그는 공부 기록용 개인 블로그입니다.

    혹시 틀린 부분이 있다면 지적 부탁드립니다.

    감사합니다!

     

     

    참고

    https://limkydev.tistory.com/51

    https://dev-ahn.tistory.com/121

    http://tcpschool.com/java/java_intro_programming

    https://hoonmaro.tistory.com/19

Designed by Tistory.