회원가입을 하면 원하는 문장을
저장할 수 있어요!
다음
AWS 이용 중이라면 최대 700만 원 지원받으세요
모든 프로그램에는 시작과 끝이 있습니다. 개발자가 코드를 작성하고 실행하면 JVM에서 프로그램이 실행된 후 종료됩니다. 이때, JVM 상에서 어떤 식으로 동작하며 개발자가 작성한 코드는 어떤 식으로 돌아가고 메모리는 어떻게 구성되어 있기에 객체지향언어라고 말하는지에 대해 설명하려고 합니다. 오늘은 간단한 이론을 먼저 알아보고 다음 편에서 더 자세한 자바(Java) 지식에 대해 설명하겠습니다.
회원가입을 하면 원하는 문장을
저장할 수 있어요!
다음
회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!
확인
모든 프로그램에는 시작과 끝이 있습니다. 개발자가 코드를 작성하고 실행하면 JVM에서 프로그램이 실행된 후 종료됩니다. 이때, JVM 상에서 어떤 식으로 동작하며 개발자가 작성한 코드는 어떤 식으로 돌아가고 메모리는 어떻게 구성되어 있기에 객체지향언어라고 말하는지에 대해 설명하려고 합니다. 오늘은 간단한 이론을 먼저 알아보고 다음 편에서 더 자세한 자바(Java) 지식에 대해 설명하겠습니다.
자바 JVM(Java Virtual Machine)은 자바로 작성된 프로그램을 실행하는 데 사용되는 가상 머신입니다. JVM은 자바 어플리케이션을 바이트코드로 변환하고, 이 바이트코드를 OS(운영체제)에 상관없이 실행할 수 있게 합니다. 이렇게 함으로써 자바는 플랫폼 독립적인 특성을 가집니다.
JAR 파일은 자바 애플리케이션과 관련된 클래스 파일, 메타데이터, 리소스 파일 등을 하나의 압축 파일로 묶은 것입니다. 이 파일은 자바 애플리케이션을 쉽게 배포하고 설치할 수 있도록 하는 데 도움이 됩니다. 또한, JAR 파일은 자바 라이브러리를 포함할 수 있어, 재사용 가능한 코드 모듈을 효율적으로 관리할 수 있습니다. 즉 개발자가 개발하기 위해 필요한 기능을 압축한 것을 JAR이라고 합니다.
WAR 파일은 웹 애플리케이션과 관련된 파일들을 하나의 압축 파일로 묶은 것입니다. JSP, 서블릿(Servlet), 클래스 파일, XML 설정 파일, 웹 리소스 (HTML, CSS, 자바스크립트, 이미지 등) 등 웹 애플리케이션 구성 요소를 포함합니다. WAR 파일은 웹이나 애플리케이션서버에 배포할 수 있으며, 이를 통해 웹 애플리케이션을 쉽게 설치하고 관리할 수 있습니다. JAR은 웹으로 실행이 불가능하지만, WAR로 묶었을 때는 사용이 가능합니다.
EAR 파일은 자바 기반의 엔터프라이즈 애플리케이션을 패키징 하는 데 사용되는 파일 형식입니다. EAR 파일은 웹 애플리케이션 (WAR 파일), EJB(Enterprise Java Bean) 모듈, 자바 어플리케이션 (JAR 파일) 및 관련 리소스를 포함하며, 이들은 각각 서로 다른 계층의 구성 요소를 나타냅니다. EAR 파일을 사용하면 여러 모듈과 리소스가 포함된 대규모 엔터프라이즈 애플리케이션을 하나의 파일로 통합하여 배포하고 관리할 수 있습니다. 주로 자바 EE 애플리케이션 서버에서 사용되며, 서버 관리자는 EAR 파일을 통해 애플리케이션의 배포와 관리를 손쉽게 수행할 수 있습니다.
요약하면, JAR, WAR, EAR 파일은 각각 자바, 웹, 엔터프라이즈 형식의 애플리케이션을 패키징하고 배포하는 데 사용되는 파일 형식입니다. 이러한 파일 형식을 사용하면 애플리케이션의 구성 요소와 리소스를 효율적으로 관리하고 배포 및 설치를 간소화할 수 있습니다.
프로그램이 실행되어 종료되기까지의 과정을 라이프 사이클이라고 합니다. 자바 실행 과정은 소스코드 작성, 컴파일, 클래스 로딩, 바이트코드 검증, Just-In-Time, 실행, 메모리 관리, 종료로 총 8단계로 나눌 수 있습니다. 각각의 단계에서 어떠한 동작이 발생하는지에 대해 설명하려고 합니다.
개발자는 텍스트 에디터를 사용하여 자바 소스 코드를 작성합니다. 자바 소스 코드는 .java 확장자를 가지고 있습니다. 이렇게 작성된 소스코드는 컴파일 과정을 거쳐 .class 로 변환됩니다. 소스코드를 작성할 때는 자바 언어의 표준 라이브러리(Java Standard Library)를 활용하거나 사용자 정의 라이브러리를 사용하여 재사용성을 높일 수 있습니다.
소스코드의 구문 및 의미를 분석하여 바이트 코드로 변환합니다 쉽게 풀어서 설명하면 .java 형태로 개발된 코드를 .class 파일로 바꿔주는 작업을 합니다. 이 과정에서 자바 컴파일러의 문법 분석기는 자바 코드의 구문을 검사하고, 올바르게 작성되어 있는지를 검증합니다. 또한 자바 소스 코드가 다른 클래스나 라이브러리를 사용할 경우, 이를 참조할 수 있도록 해당 클래스나 라이브러리를 검색합니다. 이때, 사용되는 것이 클래스패스(Classpath)입니다. 클래스 패스는 컴파일러가 참조할 클래스나 라이브러리 위치를 지정해 주는 역할을 합니다.
클래스 로더는 JVM의 일부로, .class 파일을 메모리에 로드하는 역할을 합니다. 개발자가 클래스 로더의 역할에 대해 알게 된다면, 자바와 스프링의 구조에 대해 디테일하게 알 수 있습니다. 클래스 로더는 클래스를 로드한 후, 링크하고 초기화합니다. 링크는 클래스나 인터페이스의 레퍼런스를 해결하고, 필드와 메소드를 준비하는 과정을 의미하며, 초기화는 스태틱(static) 블록을 실행하고, 스태틱 변수를 초기화하는 과정을 의미합니다. 클래스 로더는 로드되는 클래스의 종류에 따라서 우선순위를 다르게 부여하고 부트스트랩 클래스 로더, 확장 클래스 로더, 시스템 클래스 로더로 JVM에 내장되어 있으며, 사용자 정의 클래스 로더로 구분할 수 있습니다.
부트스트랩 클래스 로더: JVM을 시작할 때, 자바 가상 머신은 부트스트랩 클래스 로더를 이용하여 기본적으로 제공되는 자바 클래스들을 로드합니다. 대표적으로 JVM의 핵심 라이브러리인 rt.jar가 있습니다. 부트스트랩 클래스 로더는 JDK(자바 개발 도구)에 내장되어 있으며, 가장 먼저 클래스를 로드하는 역할을 담당합니다.
확장 클래스 로더: 확장 클래스 로더는 표준 클래스 로더와 시스템 클래스 로더의 중간 단계에 해당합니다. 이 로더는 플랫폼별로 클래스를 로드합니다. 예를 들어, JDK가 설치된 경로에 있는 클래스들을 로드합니다.
시스템 클래스 로더: 시스템 클래스 로더는 애플리케이션 클래스들을 로드합니다. 애플리케이션 클래스는 앱개발자가 작성한 클래스들을 포함합니다. 시스템 클래스 로더는 확장 클래스 로더의 하위 단계에 해당하며, 클래스 패스에 지정된 경로에 있는 클래스들을 로드합니다. 이때, 시스템 클래스 로더는 애플리케이션 클래스 패스에 있는 클래스 파일을 검색하고 없을 시 에러를 발생시킵니다.
추가로 라이브러리의 jar 파일은 시스템 클래스 로더와 확장 클래스 로더 그리고 사용자 정의 클래스 로더 중 하나에 의해 로드되지만 일반적으로, 시스템 또는 확장 클래스 로더에 의해 로드됩니다. 이때, 시스템 클래스 로더는 JRE(자바 라이브러리, 자바 가상머신의 모둠)의 라이브러리 디렉터리(lib/)와 애플리케이션 클래스패스를 검색하며, 확장 클래스 로더는 JRE의 확장 디렉토리(ext/)를 검색합니다.
부트스트랩 클래스 로더: 부트스트랩 클래스 로더는 JVM의 핵심 라이브러리인 rt.jar 등의 클래스를 로드하는 역할을 합니다. 자바 에이전트가 부트스트랩 클래스 로더에 접근하려면, 자바 가상 머신에 '-Xbootclasspath/a:' 옵션을 사용하여 클래스 경로를 추가해야 합니다.
클래스 로더는 바이트 코드를 로딩한 후, JVM(자바 가상 머신) 내부에서 바이트 코드의 유효성을 검사합니다. 이 과정에서 JVM은 스택을 검사하고, 사용되지 않는 로컬 변수를 제거하는 등의 작업을 수행합니다. 유효하지 않은 바이트 코드는 JVM에서 실행되지 않으며, 실행 중 예기치 못한 오류가 발생할 수 있습니다.
바이트 코드 검증은 JVM의 안전성과 보안성을 보장하기 위한 과정입니다. 이 과정에서 바이트 코드의 구문 및 의미를 분석하고, 유효성을 검증합니다. 예를 들어, 메소드 호출이 올바르게 수행되었는지, 바이트 코드 내부에 선언된 변수가 유효한지 등을 검사합니다. 이 검사에서 유효하지 않은 바이트 코드가 발견되면, JVM은 이를 실행하지 않습니다. 이를 통해 JVM은 자바 프로그램의 실행 중에 예기치 않은 오류를 방지하고, 안정성을 높이는 역할을 합니다.
JVM은 자바 바이트 코드(Java Bytecode)를 실행하는데, 일반적으로는 인터프리터 방식으로 동작한다. 인터프리터 방식은 바이트 코드를 한 줄씩 읽어들이면서 실행하는 방식으로, 실행 속도가 느리다는 단점이 있다.
이를 해결하기 위해 Just-In-Time 컴파일러(JIT compiler)를 도입하여 이러한 속도 저하를 보완했다. Just-In-Time 컴파일러는 인터프리터 방식으로 바이트 코드를 실행할 때, 실행 속도가 느린 부분을 파악하여 해당 부분을 네이티브 코드(native code)로 변환하고, 이후에는 인터프리터 대신에 네이티브 코드를 직접 실행하는 방식으로 동작한다.
이 방식을 통해, 자바 애플리케이션의 실행 속도를 대폭 향상시킬 수 있다. 또한 JIT 컴파일러는 애플리케이션의 실행 패턴을 분석하여 최적화된 코드를 생성하므로, 애플리케이션의 실행 속도를 최적화할 수 있다.
JIT(Just-In-Time) 컴파일러는 크게 두 가지 방식으로 동작합니다.
첫째, 인터프리터 모드로 동작하면서, 런타임에 실행되는 바이트 코드를 추적하여 해당 코드를 네이티브 코드로 컴파일합니다.
둘째, AOT(Ahead-of-Time) 모드로 동작하면서, 프로그램이 시작될 때 모든 코드를 네이티브 코드로 변환하여 미리 컴파일합니다. 이렇게 미리 컴파일된 코드는 프로그램이 실행되는 동안 인터프리터 모드에서 실행됩니다.
기나긴 과정을 거쳐 이제 개발자가 작성한 코드가 실행됩니다. 위 과정을 통해 변환된 기계어 코드는 JVM에서 실행됩니다. 이때, JVM은 자바 스레드(Thread)를 생성하여 여러 작업을 동시에 처리할 수 있으며, 스레드는 동기화된 코드를 실행하거나, I/O(입력/출력) 작업을 수행할 때 유용합니다. JVM은 자바 언어에서 제공하는 가비지 컬렉터(Garbage Collector)를 사용하여 메모리 누수를 방지합니다.
JVM은 자바 프로그램에서 사용하는 메모리를 관리합니다. 이 과정에서 JVM은 메모리 할당, 해제, 가비지 컬렉션 등을 수행하여 자원의 효율성을 높이고, 메모리 누수 등의 문제를 방지합니다. JVM은 메모리를 스택(Stack)과 힙(Heap)으로 구분하여 관리하며 스택은 지역 변수와 메소드 호출을 위한 힙은 객체와 배열 등을 위한 메모리를 할당합니다. 자바의 메모리는 T메모리로 설명할 수 있으며, 해당 설명은 다음 편에서 추가적으로 설명할 예정입니다.
자바 프로그램이 실행을 마치면, JVM은 프로그램에서 사용한 자원을 해제하고 종료됩니다. 이때, 사용한 자원에는 파일, 네트워크 연결, 데이터베이스 커넥션 등이 포함됩니다. 또한, JVM은 일정 시간 동안 사용되지 않는 객체를 메모리에서 해제하며, 이를 가비지 컬렉션이 수행합니다.
이번 편에선 스프링 입문자를 위한 기초적인 이론 지식에 대해 살펴봤습니다. 다음 편에서는 실무 지식에 대해 이야기해보겠습니다.
글 sh
편집 정선아 객원 에디터
요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.